# cartesian — 슬라이드 만들기 지시서 (채팅 AI용)

> 이 파일은 **ChatGPT·Claude·Gemini 같은 채팅 AI**에게 통째로 주면, 이 디자인(`cartesian`)으로 수업 슬라이드를 만들어 주도록 쓴 지시서입니다.
> 파일을 읽고 쓸 수 있는 에이전트 AI(Claude Code 등)를 쓴다면 갤러리의 **받기 .zip**을 쓰세요.

## 사용법 (사람이 읽는 안내)

1. 채팅 AI 대화창에 **이 파일을 첨부**합니다. 첨부가 안 되면 파일 내용을 **전부 복사해 붙여 넣습니다**(끝까지 빠짐없이).
2. 이어서 만들고 싶은 수업을 말합니다(**"결과는 .html 파일로 만들어 줘"**도 같이 말하면 좋습니다). 예) "6학년 2학기 과학 1단원 3~4차시, 학습 목표는 ○○○, 00초등학교, 슬라이드로 만들어 줘(장 수와 구성은 내용에 맞게 정해 줘)."
3. AI가 먼저 **장별 구성안**(장마다 제목·내용·쓸 부품)을 보여 줍니다. 마음에 들면 "좋아, 만들어 줘", 고칠 곳이 있으면 "3장은 빼고 퀴즈를 하나 더 넣어 줘"처럼 말합니다. 구성 확인 없이 바로 받고 싶으면 2번에서 "구성 확인 없이 바로 만들어 줘"라고 하세요.
4. AI가 **슬라이드.html 파일**을 만들어 줍니다. 내려받아 더블클릭하면 브라우저에서 열립니다. 방향키(→ ←)와 스페이스로 넘깁니다. 만약 파일 대신 **코드만 글로 보여 주면** "코드 말고 .html 파일로 만들어서 내려받게 해 줘"라고 다시 요청하세요. 그래도 안 되면 코드를 모두 복사해 메모장에 붙여 넣고 `슬라이드.html`로 저장합니다(파일 형식은 '모든 파일', 인코딩은 UTF-8).
5. 고치고 싶으면 AI에게 "2장 제목을 ○○로 바꿔 줘"처럼 말하면 됩니다. 중간에 코드가 끊기면 "끊긴 곳부터 이어서 출력해 줘"라고 하세요.

서비스별 팁 (메뉴 이름은 서비스마다 바뀔 수 있습니다)
- 공통: 고를 수 있다면 **생각하는(추론) 모드**나 상위 모델을 쓰세요. 긴 코드를 끝까지 정확하게 쓰는 데 차이가 큽니다.
- ChatGPT: "캔버스로 만들어 줘" 또는 "다운로드할 수 있는 .html 파일로 만들어 줘"라고 요청합니다.
- Gemini: 입력창의 **Canvas**를 켜고 요청하면 화면에서 바로 보고 내려받을 수 있습니다.
- Claude: 결과가 **아티팩트**(오른쪽 창)로 열리면 거기서 내려받습니다.
- AI가 그림 파일(이미지)을 따로 만들어 주더라도 슬라이드에는 들어가지 않습니다. 슬라이드는 .html 파일입니다.
- **AI 화면 안의 미리보기에서는 색·모양·버튼이 안 나올 수 있습니다.** 이 디자인의 공통 모양과 동작은 슬라이드를 열 때 인터넷(`https://k-slide.web.app`)에서 불러오는데, 일부 서비스의 미리보기 창은 바깥 파일을 막기 때문입니다. **내려받아 브라우저(크롬·엣지 등)로 열면 정상**으로 보입니다.

알아 둘 점
- 이 디자인의 한글 글씨체는 제목 Cafe24 Oneprettynight(400) · 본문 프리텐다드 Pretendard-Light(300)입니다. 글씨체와 공통 모양·동작은 **인터넷에서 불러오므로 슬라이드를 열 때 인터넷이 필요**합니다(영문 글꼴도 마찬가지). 인터넷 없이 발표하려면 갤러리의 **받기 .zip**(모든 것이 파일 안에 들어 있음)을 쓰세요.
- AI가 긴 코드를 일부 생략하거나 어긋나게 쓸 수 있습니다. 열어서 한 번 확인하세요. 안 열리거나 깨지면 "코드가 생략되었어. 완성된 HTML 하나로 처음부터 끝까지 다시 출력해 줘"라고 요청합니다.
- 사진·학생 이름 같은 개인정보는 AI에게 넣지 마세요.

## 라이선스

폰트 라이선스 안내
==================

- Cafe24 Oneprettynight: Cafe24 Oneprettynight — KERIS 학교 안심폰트(https://copyright.keris.or.kr/wft/fntDwnld, 전체 OFL 안내)에서 받은 TTF (2026-10-07) / 파일 안 저작권: Copyright (c) 2020 by Cafe24. All rights reserved.
  파일: Cafe24Oneprettynight-v2.0.ttf
- 프리텐다드 Pretendard-Light: 프리텐다드 — 프리텐다드 (Pretendard) — 길형진 (orioncactus) / 눈누: https://noonnu.cc/font_page/694
  파일: Pretendard-Light.ttf

SIL Open Font License 1.1 요약
- 폰트를 자유롭게 사용·복제·수정·재배포할 수 있습니다(폰트 파일 단독 판매는 불가).
- 수정본(글자를 줄인 서브셋 포함)은 원래 폰트의 '예약 이름'을 쓰지 못할 수 있습니다.
- 재배포할 때는 저작권 표시와 라이선스 문구를 함께 넣어야 합니다.
- 전문: https://openfontlicense.org

학교안심 글꼴과 easy3D 폴더의 글꼴은 사용자가 OFL로 확인한 내용을 따랐습니다. 배포 전에 각 배포처에서 최신 라이선스를 다시 확인하세요.

design.md 라이선스 (MIT)
=======================
design.md는 frontend-slides(https://github.com/zarazhangrui/frontend-slides)의 템플릿을 바탕으로 한 것이며, 아래 MIT 라이선스를 따릅니다.

MIT License

Copyright (c) 2025 Zara Zhang

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

---

# ▼▼▼ 여기부터 AI에게 주는 지시서 ▼▼▼

(이 줄 위의 '사용법'과 '라이선스'는 사람을 위한 안내입니다. AI는 아래 지시서를 따르세요.)

## 0. 당신(AI)의 일

당신은 슬라이드 제작 도우미입니다. 사용자가 알려 주는 수업 내용으로, 아래 **디자인 규칙(1)**, **부품 사전(3)**, **HTML 뼈대(4)**를 지켜 **브라우저에서 바로 열리는 슬라이드 HTML 파일 하나**를 만듭니다.
이 디자인의 공통 CSS(글씨체·색·부품 모양)와 동작 엔진은 사이트에 올려 둔 파일이라, 뼈대의 `<link>`·`<script src>` 두 줄이 불러옵니다. **당신이 쓰는 것은 슬라이드 HTML(`<section class="slide">`들과 내비)과, 꼭 필요할 때만 '추가 부품' CSS뿐입니다.** 공통 CSS의 내용은 참고용으로 5에 있습니다.

### 진행 순서
1. 사용자가 아직 수업 내용을 말하지 않았다면, 먼저 아래를 짧게 물어보세요: 학교급·학년·과목, 단원과 차시, 학습 목표, 학교 이름(선택), 원하는 장 수(말하지 않으면 내용 분량에 맞게 정함).
2. **장별 구성안을 먼저 보여 주고 확인을 받습니다**(아래 '구성은 내용이 정합니다'). 이때는 코드를 쓰지 마세요.
3. 확인을 받으면 HTML을 만들고, 내보내기 전에 아래 '내보내기 전 점검'을 하나씩 확인합니다.
- 내용은 사용자가 준 것만 쓰고, **숫자·사실·출처를 지어내지 마세요.** 모르면 묻거나 "(예시)"라고 표시하세요.
- **사용자가 주지 않은 사실(연도·기록·수치·등재·'세계 최고'·'가장 ○○하다' 같은 말)을 덧붙이고 싶으면, 구성안에 '추가 사실'로 따로 적어 확인을 받으세요.** 확인받지 않은 사실은 슬라이드에 넣지 않습니다. 널리 알려진 이야기라도 정확한 대상을 쓰세요(예: 유네스코 세계기록유산에 오른 것은 '한글'이 아니라 《훈민정음》 해례본이라는 책).

### 반드시 지킬 것
1. **디자인 규칙(1)을 어기지 마세요.** 색·글꼴·배치·장식·움직임 규칙과 '하지 말 것'을 그대로 따릅니다. 규칙에 없는 효과(임의의 애니메이션, 새 색, 새 장식)를 더하지 마세요.
2. **뼈대(4)의 공통 파일 두 줄을 그대로 두세요.** `<link rel="stylesheet" href="https://k-slide.web.app/kit/v1/cartesian.css">`(head 안)와 `<script src="https://k-slide.web.app/kit/v1/cartesian.js"></script>`(body 맨 끝)는 주소 한 글자도 바꾸거나 지우지 마세요. **공통 CSS(5)나 엔진을 HTML 안에 옮겨 쓰거나, 줄이거나, 비슷하게 새로 짜지 마세요**(이미 불러오므로 같은 규칙을 또 쓰면 서로 부딪혀 깨집니다). `<style>`에는 '추가 부품' 줄과 그 아래에 직접 정의한 클래스만 둡니다. 엔진이 쓰는 속성 이름(`data-steps`, `data-s`, `data-quiz`, `data-opt`, `data-act`, `data-blank` 등)은 5의 엔진 사용법대로 씁니다.
3. **클래스는 부품 사전(3)과 공통 CSS(5)에 있는 것만 쓰세요.** 없는 클래스 이름을 지어 쓰면 아무 모양도 적용되지 않아 배치가 무너집니다(창이 좁아지고 빈 공간이 생김). 새 부품이 꼭 필요하면 `<style>`의 '추가 부품' 주석 줄 **아래에** 그 클래스를 직접 정의하세요(디자인 규칙의 색·선·글꼴만 사용). 모양을 `style="…"`로 하나하나 지정하는 것보다 부품 클래스를 쓰는 쪽이 낫습니다.
   - **새 배치를 만들기 전에, 예시 장의 배치 클래스로 할 수 있는지 먼저 보세요.** 직접 만든 배치는 화면을 볼 수 없는 상태에서 쓰기 때문에 깨질 위험이 큽니다. 예시 배치로 안 될 때만 새로 정의합니다.
4. **슬라이드의 장 수·순서·내용은 사용자 수업에 맞게 새로 구성하세요.** 뼈대의 슬라이드는 '계절의 변화' 예시이므로 그 문구는 하나도 남기지 마세요. 장을 늘리거나 줄이거나 순서를 바꾸면 **내비 점 개수와 쪽 표시(예: 01 / 06)를 실제 장 수에 맞추세요.** 뼈대의 6번째 장은 이 디자인의 대표 장치를 눌러 보여 주는 안내 장이므로, 그 부품·움직임(예: data-demo 시연 버튼과 .play 상태)만 참고하고 디자인 안내 문구는 남기지 마세요. 아래 '구성은 내용이 정합니다'를 따르세요.
5. **글씨체는 바꾸지 마세요.** 한글 글씨체(제목 Cafe24 Oneprettynight(400) · 본문 프리텐다드 Pretendard-Light(300))는 공통 CSS가 불러옵니다. `@font-face`를 새로 쓰지 말고, 글꼴은 `var(--kt)`(제목)·`var(--kb)`(본문)·`var(--ka)`(포인트) 변수로만 지정하세요.
6. **글자 크기와 화면 채우기** (슬라이드는 1920×1080 기준으로 그려져 화면 크기에 맞게 통째로 줄어듭니다)
   - 읽어야 하는 글(본문·설명·표 내용·보기)은 **28px 이상**, 보조 글(캡션·주석)은 **22px 이상**으로 씁니다. 창 제목줄·쪽 번호·작은 라벨 같은 장식 글자는 디자인 규칙의 크기를 따릅니다.
   - 창·판·카드가 **화면의 대부분을 채우게** 하세요. 한쪽에 작게 몰리거나 큰 빈 공간이 남으면 안 됩니다. 내용이 적은 장은 글자와 그림을 키우거나 다른 장과 합칩니다.
   - **높이 예산**: 장 제목과 아래 내비를 빼면 본문에 쓸 수 있는 높이는 대략 **650~750px**입니다. 모든 내용이 1920×1080 안에 들어가야 하고, 넘친 부분은 잘려서 보이지 않습니다. 쓰기 전에 줄 수 × 줄 높이(글자 크기의 약 1.5배)로 높이를 어림해 보세요.
   - **카드 규칙**: 한 장에 카드(칸)를 4개 이상 놓으면 카드마다 글은 **3줄 이하**로 줄입니다. 글이 들어가는 칸은 **너비 400px 이상**으로 두고(그림+글을 나란히 놓을 때는 글 칸 기준), 한 줄에 몇 글자밖에 안 들어가게 좁히지 마세요. 카드를 두 줄로 쌓아야 하면 그 줄들의 높이 합이 높이 예산 안에 드는지 확인합니다.
   - 제목은 **두 줄 이내**로 씁니다. 표지 제목은 한 줄에 15자 안팎으로 끊어 줄을 바꾸세요. 글이 창 밖으로 넘치거나 잘리면 글자를 줄이지 말고 문장을 짧게 고칩니다.
   - 한글은 단어 중간에서 줄이 바뀌지 않게(`word-break:keep-all`) 합니다(공통 CSS에 이미 들어 있음).
7. 저작권이 있는 글·그림·사진을 가져오지 마세요. **사용자가 요청하지 않으면 그림 파일(이미지 생성)을 따로 만들지 마세요. 슬라이드에 필요한 그림은 HTML 안에서 SVG·CSS로 그립니다.**

### 구성은 내용이 정합니다
- 예시 덱(deck.html)은 이 디자인의 **부품 견본**입니다. 따라야 할 장 구성이 아닙니다. 예시의 장 순서·장 수·제목 짜임·문장 구조를 그대로 따라 하지 마세요.
- 사용자가 준 내용을 먼저 살펴 **필요한 장 수와 장별 역할을 직접 정하세요.** 내용이 적으면 3~4장, 많으면 8장 이상도 괜찮습니다.
- **코드를 쓰기 전에 장별 구성안(장마다 제목 · 전할 내용 한 줄 · 쓸 부품)을 먼저 보여 주고 확인을 받으세요.** 사용자가 고치라고 하면 고친 구성안을 다시 보여 주고, "좋아", "만들어 줘"라고 하면 그때 만듭니다. 사용자가 처음부터 "구성 확인 없이 바로 만들어 줘"라고 했으면 이 단계는 건너뜁니다.
- 아래 부품 중 **필요한 것만 골라 쓰세요.** 안 쓰는 부품이 있어도 되고(예: 퀴즈 없는 덱), 같은 부품을 여러 장에 쓰거나 한 장에 섞어 써도 됩니다.
  · 표지 · 단계 버튼이 있는 흐름(data-steps) · 큰 숫자와 통계 · 그래프 · 비교와 표 · 목록과 인용 · 퀴즈와 다시 풀기 · 빈칸 채우기 · 시연 버튼(data-demo)
- 장마다 전하는 메시지는 하나로 하고, 같은 모양의 장이 연달아 나오지 않게 하세요.
- 지켜야 하는 것은 디자인 규칙(design.md)과 동작 엔진입니다. 자유로운 것은 장의 수·순서·구성입니다.

### 출력 방식
- **결과물은 '.html 파일'로 주세요.** 파일 이름은 슬라이드.html, 형식은 UTF-8 HTML 문서 하나입니다. 파일을 만들거나 내려받게 해 주는 기능(아티팩트·캔버스·코드 실행 환경·파일 첨부 등)이 있으면 **반드시 그 기능으로 .html 파일을 만들어 내려받거나 열 수 있게** 하세요. 코드만 글로 보여 주고 끝내지 마세요.
- 파일을 만들 수 있는 기능이 **전혀 없을 때만**, 설명은 한두 줄로 줄이고 **완성된 HTML 전체를 ```html 코드 블록 하나**로 출력하세요(이때 사용자가 직접 .html로 저장합니다).
- **`...`, "(이하 동일)", "(생략)" 같은 생략 표시를 쓰지 마세요.** `<!DOCTYPE html>`부터 `</html>`까지 전부 씁니다.
- 너무 길어 끊길 것 같으면 먼저 쓰지 말고, 사용자에게 "장 수를 줄일까요?"라고 묻거나, 끊기면 사용자가 "이어서"라고 할 때 **끊긴 글자 바로 다음부터** 이어 쓰세요.
- **미리보기 창에서 색·모양·버튼이 안 보여도 고치지 마세요.** 공통 CSS·엔진은 인터넷 주소(`https://k-slide.web.app`)에서 불러오는데, 일부 미리보기 창은 바깥 파일을 막습니다. 내려받아 브라우저로 열면 정상입니다. 이때 공통 CSS나 엔진을 HTML 안에 직접 써 넣으면 안 됩니다. 사용자에게 "내려받아 브라우저로 열어 보세요"라고 안내하세요.
- 파일을 코드(파이썬 등)로 써서 만든다면, HTML 전체를 **원문 그대로의 문자열**로 쓰세요(예: 파이썬은 따옴표 세 개짜리 raw 문자열). 백슬래시(`\`)가 다른 문자로 바뀌어 깨지는 일을 막기 위해서입니다. 새로 쓰는 CSS·JS에서도 `\00a0` 같은 이스케이프 대신 실제 문자를 쓰세요.
- 파일로 줬다면 "슬라이드.html을 내려받아 더블클릭하세요(열 때 인터넷 필요)"라고, 코드 블록으로 줬다면 "코드를 모두 복사해 메모장에 붙여 넣고 슬라이드.html로 저장한 뒤 더블클릭하세요(열 때 인터넷 필요)"라고 한 줄로 안내하세요.

### 내보내기 전 점검 (하나라도 아니면 고친 뒤 내보내기)
1. HTML에 쓴 클래스가 모두 부품 사전(3)·공통 CSS(5)·'추가 부품' 칸에 정의되어 있는가?
2. 공통 파일 두 줄(`<link>`·`<script src>`)이 주소 그대로 있고, 공통 CSS·엔진을 HTML 안에 옮겨 쓰지 않았는가? `@font-face`를 새로 쓰지 않았는가?
3. 장 수 = 내비 점 개수 = 쪽 표시 숫자인가?
4. 모든 장의 내용이 1920×1080 안에 들어가는가(높이 예산, 카드 규칙)? 제목·글이 창 밖으로 넘치거나 잘리지 않는가(특히 표지 제목과 마지막 장)? 읽는 글이 28px 이상이고, 화면에 큰 빈 공간이 없는가?
5. '계절의 변화' 예시 문구나 디자인 안내 문구가 남아 있지 않은가?
6. 사용자가 주지 않았고 확인도 받지 않은 사실을 넣지 않았는가?
7. `...`·"(생략)" 같은 생략이 없고, `<!DOCTYPE html>`부터 `</html>`까지 다 있는가?
8. 사용자가 요청하지 않은 그림 파일을 따로 만들지 않았는가?

---

## 1. 디자인 규칙 (`cartesian` design.md)

````markdown
---
version: alpha
name: Cartesian
description: A quiet, museum-catalog editorial system built on Playfair Display serif headlines, Inter sans body, and a five-tone warm-stone palette. The aesthetic is "consulting deck meets architectural monograph" — minimal geometric line decorations (thin circles, dashed arcs, vertical and horizontal hairlines) drift behind content, suggesting drafting paper and compass work. Every divider is a single 1px line in a muted taupe; nothing is bold, nothing is loud. The cultural reference is Massimo Vignelli's editorial work, the Cooper Hewitt catalog, and pencil-and-tracing-paper urban planning documents.

colors:
  bg-primary: "#EDE8E0"
  bg-secondary: "#E2DBD1"
  text-primary: "#1A1A1A"
  text-secondary: "#5A5A5A"
  accent: "#8A8178"
  line: "#B8B0A4"
  white-overlay: "rgba(255, 255, 255, 0.3)"

typography:
  display:
    fontFamily: "Playfair Display, serif"
    fontSize: "clamp(3rem, 6vw, 5.5rem)"
    fontWeight: 400
    lineHeight: 1.1
  h1:
    fontFamily: "Playfair Display, serif"
    fontSize: "clamp(2.5rem, 5vw, 4.5rem)"
    fontWeight: 400
    lineHeight: 1.1
  h2:
    fontFamily: "Playfair Display, serif"
    fontSize: "clamp(1.8rem, 3.5vw, 3rem)"
    fontWeight: 400
    lineHeight: 1.1
  h3:
    fontFamily: "Playfair Display, serif"
    fontSize: "clamp(1.2rem, 2vw, 1.6rem)"
    fontWeight: 400
    lineHeight: 1.1
  stat-figure:
    fontFamily: "Playfair Display, serif"
    fontSize: "2rem"
    fontWeight: 400
    lineHeight: 1
  agenda-numeral:
    fontFamily: "Playfair Display, serif"
    fontSize: "1.5rem"
    fontWeight: 400
    lineHeight: 1
  team-initial:
    fontFamily: "Playfair Display, serif"
    fontSize: "2rem"
    fontWeight: 400
    lineHeight: 1
  quote-mark:
    fontFamily: "Playfair Display, serif"
    fontSize: "5rem"
    fontWeight: 400
    lineHeight: 1
  card-headline:
    fontFamily: "Playfair Display, serif"
    fontSize: "1.3rem"
    fontWeight: 400
    lineHeight: 1.1
  timeline-headline:
    fontFamily: "Playfair Display, serif"
    fontSize: "1.2rem"
    fontWeight: 400
    lineHeight: 1.1
  body:
    fontFamily: "Inter, sans-serif"
    fontSize: "clamp(0.9rem, 1.2vw, 1.1rem)"
    fontWeight: 400
    lineHeight: 1.6
  body-sm:
    fontFamily: "Inter, sans-serif"
    fontSize: "0.9rem"
    fontWeight: 400
    lineHeight: 1.6
  subtitle:
    fontFamily: "Inter, sans-serif"
    fontSize: "clamp(1rem, 1.5vw, 1.3rem)"
    fontWeight: 400
    lineHeight: 1.5
  attribution:
    fontFamily: "Inter, sans-serif"
    fontSize: "0.85rem"
    fontWeight: 400
    lineHeight: 1.4
    letterSpacing: 2px
    textTransform: uppercase
  label:
    fontFamily: "Inter, sans-serif"
    fontSize: "0.75rem"
    fontWeight: 500
    lineHeight: 1
    letterSpacing: 3px
    textTransform: uppercase
  micro:
    fontFamily: "Inter, sans-serif"
    fontSize: "0.7rem"
    fontWeight: 400
    lineHeight: 1
    letterSpacing: 2px
    textTransform: uppercase

spacing:
  pad-y: "4vh"
  pad-x: "4vw"
  gap-xl: "6vw"
  gap-lg: "5vw"
  gap-md: "3vw"
  gap-sm: "2vh"
  card-pad: "4vh 2vw"

canvas:
  width: 100vw
  height: 100vh

components:
  card:
    border: "1px solid {colors.line}"
    padding: "{spacing.card-pad}"
    background: "{colors.white-overlay}"
    description: "Tracing-paper card — 1px taupe outline with semi-transparent white fill that lets the canvas tone bleed through. No radius, no shadow."
  card-icon:
    width: 40px
    height: 40px
    border: "1px solid {colors.line}"
    borderRadius: "50%"
    color: "{colors.accent}"
    fontSize: "1rem"
    description: "Small ringed circle (40px) containing a 1–3 character Roman numeral or letter in accent taupe."
  agenda-row:
    padding: "2vh 0"
    borderBottom: "1px solid {colors.line}"
    description: "List row separated only by a 1px taupe hairline. Numeral at left, label at right."
  timeline-rule:
    height: "1px"
    background: "{colors.line}"
    description: "Single horizontal 1px taupe line connecting timeline items. No nodes, no markers — just the line."
  vertical-line:
    width: "1px"
    height: "100%"
    background: "{colors.line}"
    opacity: 0.3
    description: "Optional decorative vertical hairline anchored at left edge (default 8vw from edge) at low opacity. Provides drafting-paper grid feel."
  horizontal-accent:
    width: "20vw"
    height: "1px"
    background: "{colors.text-primary}"
    description: "Single short ink-black 1px horizontal line used as a strong accent rule. Black, not taupe."
  geo-circle:
    border: "1px solid {colors.line}"
    borderRadius: "50%"
    opacity: 0.5
    description: "Thin solid taupe ring at low opacity, used as decorative geometry behind content."
  geo-arc:
    border: "1px dashed {colors.line}"
    borderRadius: "50%"
    opacity: 0.3
    description: "Thin dashed taupe ring at very low opacity, paired with geo-circle to suggest compass construction."
  geo-decoration:
    border: "1px solid {colors.line}"
    borderRadius: "50%"
    description: "Large decorative ring (30–50vw diameter) anchored to a corner or center. Always pairs with a ::before pseudo-element rendering a smaller dashed ring inside it, suggesting concentric drafting."
  geo-ring:
    width: "50vw"
    height: "50vw"
    border: "1px solid {colors.line}"
    borderRadius: "50%"
    opacity: 0.3
    description: "The largest geometric decoration variant — a 50vw centered ring with an inner ::before dashed ring at 70% diameter."
  image-placeholder:
    background: "{colors.bg-secondary}"
    border: "1px solid {colors.line}"
    description: "Solid taupe-tinted block with two crossed 1px diagonal hairlines via ::before/::after at +30° and -30°, suggesting an X over a blank frame. Holds a small uppercase label centered."
  team-photo:
    width: "12vw"
    height: "12vw"
    borderRadius: "50%"
    border: "1px solid {colors.line}"
    background: "{colors.bg-secondary}"
    description: "Circular portrait frame (12vw) in slightly darker stone, ringed in taupe, holding a single Playfair initial in accent taupe at center."
  nav-arrow:
    width: 40px
    height: 40px
    border: "1px solid {colors.line}"
    background: "transparent"
    description: "Square 40px button with 1px taupe border holding an arrow glyph. Hover state inverts to ink fill with cream text."
  nav-dot:
    width: 8px
    height: 8px
    borderRadius: "50%"
    background: "{colors.line}"
    description: "Small taupe dot at right edge as navigation indicator. Active state shifts to ink and scales 1.3."
  chart-stroke-primary: "{colors.text-primary}"
  chart-stroke-comparison: "{colors.line}"
  chart-comparison-dash: "5, 5"
  chart-grid-color: "{colors.bg-secondary}"
  chart-axis-tick-color: "{colors.accent}"
---

## Frontend Slides Fixed-Stage Policy

When this design system is used by the `frontend-slides` skill, generate the final deck as a **fixed 1920×1080 stage** that scales uniformly to the browser viewport. The deck should preserve a 16:9 slide canvas on every screen, including phones; it may letterbox or pillarbox, but it should not reflow slide content for mobile.

This policy has higher priority than any source-template responsive behavior described later in this file. If a later section says the original template is viewport-fluid, treat that as source history only, not as the target generation model for `frontend-slides`.

This policy applies even if the source template was originally implemented with viewport-fluid CSS such as `100vw`, `100vh`, `vw`, `vh`, or `clamp()`. Treat those values as design proportions to translate into 1920×1080 stage coordinates, not as live responsive rules in the generated deck.

Use `deck-stage.js` or an equivalent inline stage scaler for final output: render each slide at 1920×1080, scale the whole stage with one transform, and verify rendered screenshots for both text overflow and panel overlap.


## Overview

Cartesian is a **quiet museum-catalog editorial system**. Its defining premise is **restraint through 1px lines**. Every structural element — list separators, agenda rules, timeline connectors, card borders, table dividers — is a single 1px line in a muted taupe `{colors.line}`. There are no thick borders, no fills, no shadows, no rounded surfaces. Hierarchy is built through type contrast and negative space; depth does not exist in the conventional sense.

The typeface stack is a literary-monograph pairing. **Playfair Display** — a high-contrast didone-influenced serif — carries every headline, every stat numeral, every card title, every team initial, every quote mark. Playfair runs at weight 400 (regular) almost exclusively — there is no use of bold or 700-weight Playfair in the system. The thin-stroke didone aesthetic depends on letting the letterforms breathe at modest weights. **Inter** — a clean modern grotesque — carries every body paragraph, every subtitle, every label, every attribution. Inter runs at 400 for body and 500 for labels. The pairing creates the system's editorial voice: serif statements + clean sans supporting structure.

The palette is **five warm stones plus ink**. The canvas is `{colors.bg-primary}` — a warm sandstone off-cream. A slightly deeper stone `{colors.bg-secondary}` provides subtle region differentiation (image placeholders, team photo frames). Ink `{colors.text-primary}` is the headline color; medium gray `{colors.text-secondary}` is body. A warmer taupe `{colors.accent}` carries labels, attribution, and small numerals. The lightest taupe `{colors.line}` is the universal 1px line color. There are no accent colors in the populist sense — no red, no orange, no blue. The palette is stone, stone, stone, ink, ink. The only "color" in the system is type contrast.

Depth is **entirely absent in the conventional sense**. There are no shadows, no elevated cards, no rounded surfaces, no gradients. Atmosphere is created by **geometric line decorations**: thin solid and dashed circles in `{colors.line}` at 20–50% opacity drift behind content as if drawn on tracing paper with a compass. These do not create hierarchy — they create mood. The decorative geometry signals "drafted, considered, precise."

**Density philosophy: sparse and breathing.** Cartesian reads as elegant when sparse and broken when crowded. A correctly composed slide pairs one Playfair headline with one body paragraph, or one chart with one short caption, framed by generous negative space. Most slide composition uses centered or asymmetric two-column layouts with `5–6vw` gutters and significant vertical breathing room. The decorative compass arcs reinforce the sparseness — they are most effective when there is room around them. A slide that feels broken in this system is one packed edge-to-edge with content; the correct density is "one clear idea, well-framed, on stone paper."

**Key Characteristics:**
- Warm sandstone canvas `{colors.bg-primary}` with single 1px taupe `{colors.line}` dividers as the universal structural element.
- Playfair Display serif at weight 400 for every headline/numeral/quote-mark; Inter sans for every body/label/attribution.
- Five-tone monochrome palette: two stones, two grays, one ink. No vivid accent colors anywhere.
- Decorative geometric rings (thin solid + dashed circles, 20–50% opacity) drift behind content as compass-drafted atmosphere.
- Every label, attribution, and micro-text is uppercase Inter with 2–3px letter-spacing.
- All borders are 1px hairlines; no element has a thicker border, a shadow, or a rounded fill.
- Right-edge vertical nav-dot column, bottom-left square nav-arrow buttons, bottom-right mono slide counter.
- Image placeholders carry a signature pair of crossed 1px diagonals (an X) over a stone-tinted block.

## Colors

### Stone & Ink Palette
- **Background Primary** (`{colors.bg-primary}` — #EDE8E0): The canvas. Warm sandstone off-cream — closer to "manila folder" than "white paper." This is the default slide background.
- **Background Secondary** (`{colors.bg-secondary}` — #E2DBD1): A slightly deeper stone, used for image placeholders, team-photo frames, and any region that needs subtle separation from the canvas without a colored fill or a border.
- **Text Primary** (`{colors.text-primary}` — #1A1A1A): Near-black ink. Used for headlines, stat numerals, and the special `{components.horizontal-accent}` rule. The strongest contrast color in the system.
- **Text Secondary** (`{colors.text-secondary}` — #5A5A5A): Medium warm gray. Used for all body paragraph text. Softer than ink — readable but recedes.
- **Accent** (`{colors.accent}` — #8A8178): Warm taupe. Used for labels, attributions, agenda numerals, slide counter, card-icon text, team-member role text. The system's "small text" color.
- **Line** (`{colors.line}` — #B8B0A4): Pale taupe. The universal 1px line color: card borders, agenda rules, timeline connectors, team-photo rings, nav-arrow borders, geo-decoration rings.

### Defaults
- **Default surface background**: `{colors.bg-primary}`.
- **Default headline color**: `{colors.text-primary}` — always ink, never colored, never accent-taupe. Playfair headlines are uniformly ink.
- **Default body text color**: `{colors.text-secondary}` (medium warm gray).
- **Default label / attribution / micro-text color**: `{colors.accent}` (warm taupe).
- **Default border color**: `{colors.line}` — every 1px structural border. Never use ink-black for borders except the rare `horizontal-accent` rule.
- **Default secondary surface fill**: `{colors.bg-secondary}`.
- **Default chart primary series color**: `{colors.text-primary}` (ink).
- **Default chart comparison/secondary series color**: `{colors.line}` with 5px dashed stroke.
- **Default chart grid color**: `{colors.bg-secondary}`.
- **Default chart axis tick color**: `{colors.accent}`.

Cartesian has **no accent color in the populist sense.** A red callout, a blue bar, a green stat — none of these exist. When emphasis is needed, increase type size, switch from sans to serif, or add a single 1px `horizontal-accent` rule in ink. Color is not the emphasis mechanism in this system; restraint is.

## Typography

### Font Family
The system runs on a **two-face conversation**: `Playfair Display` (serif, weights 400/600/700, italic available) carries every headline, stat numeral, quote mark, card title, and team initial; `Inter` (sans, weights 300/400/500/600) carries every body, subtitle, label, attribution, and micro-text. There is no third face.

Playfair Display is used almost exclusively at **weight 400 (regular)**. The system deliberately avoids bold Playfair — the didone aesthetic relies on thin-stroke modulation that disappears at heavier weights. Italic Playfair is available (loaded) but not exercised in the default template; reserve it for inline emphasis inside body copy.

Inter runs at weight 400 for body, weight 500 for labels and micro-text, weight 600 for the rare emphasized inline element. The contrast between Playfair's high-modulation serif and Inter's even sans is the system's primary typographic rhythm.

### Type Scale

| Token | Size | Family | Weight | Use |
|---|---|---|---|---|
| `{typography.display}` | clamp(3rem, 6vw, 5.5rem) | Playfair Display | 400 | Cover or large opening title |
| `{typography.h1}` | clamp(2.5rem, 5vw, 4.5rem) | Playfair Display | 400 | Section-opening or large closing headline |
| `{typography.h2}` | clamp(1.8rem, 3.5vw, 3rem) | Playfair Display | 400 | Primary slide headline |
| `{typography.h3}` | clamp(1.2rem, 2vw, 1.6rem) | Playfair Display | 400 | Sub-headline within a region |
| `{typography.card-headline}` | 1.3rem | Playfair Display | 400 | Card or pillar-block title |
| `{typography.timeline-headline}` | 1.2rem | Playfair Display | 400 | Timeline-step or phase headline |
| `{typography.stat-figure}` | 2rem | Playfair Display | 400 | Numerical stat figure (typically inline in a stats cluster) |
| `{typography.team-initial}` | 2rem | Playfair Display | 400 | Initial letter centered inside a team-photo circle |
| `{typography.agenda-numeral}` | 1.5rem | Playfair Display | 400 | Ordinal numeral preceding an agenda row |
| `{typography.quote-mark}` | 5rem | Playfair Display | 400 | Opening quotation glyph for a pull-quote |
| `{typography.subtitle}` | clamp(1rem, 1.5vw, 1.3rem) | Inter | 400 | Subtitle paragraph below a display headline |
| `{typography.body}` | clamp(0.9rem, 1.2vw, 1.1rem) | Inter | 400 | Standard paragraph body |
| `{typography.body-sm}` | 0.9rem | Inter | 400 | Compact body inside cards or timeline items |
| `{typography.attribution}` | 0.85rem | Inter | 400 | Attribution line below a quote, with 2px tracking + uppercase |
| `{typography.label}` | 0.75rem | Inter | 500 | Section label / eyebrow above a headline, with 3px tracking + uppercase |
| `{typography.micro}` | 0.7rem | Inter | 400 | Image label, slide counter, smallest chrome text |

### Defaults
- **Default size for the primary slide headline**: `{typography.h2}` (clamp 1.8–3rem).
- **Default size for a cover or large opening headline**: `{typography.h1}` (clamp 2.5–4.5rem); for the most expansive cover, `{typography.display}` (clamp 3–5.5rem).
- **Default size for paragraph body**: `{typography.body}` (clamp 0.9–1.1rem).
- **Default size for any inline label or eyebrow**: `{typography.label}` (0.75rem) — always 3px tracking + uppercase.
- **Default weight for any Playfair headline**: 400. Don't reach for 600 or 700.
- **Default weight for body**: 400.
- **Default weight for labels/micro**: 500.
- **Default size for a stat numeral inside a stats cluster**: `{typography.stat-figure}` (2rem). Cartesian does not have a hero-stat-numeral pattern (no 5–7rem display stat); stats are presented as inline ranks at modest scale.

When unsure, reach for `{typography.h2}` for the slide's primary text moment, not `{typography.h3}` (which is a sub-headline within a region).

### Signature Treatments
These treatments are **non-optional whenever the corresponding element type is used**:

- **Every Playfair headline, stat, quote, card title, and initial is set at weight 400.** Bold Playfair does not exist in this system. The thin-stroke didone aesthetic is the identity.
- **Every Playfair element is set in sentence case (or true title case for proper nouns).** Uppercase Playfair is not used.
- **Every Inter label, attribution, and micro-text element is uppercase with 2–3px letter-spacing.** Labels at 3px tracking; attributions and micro at 2px. Without the tracking, Inter caps read as untreated.
- **Every Playfair element is rendered in `{colors.text-primary}` (ink).** Headlines are never accent-taupe and never gray. The exception is decorative initial letters inside a circular `card-icon` or `team-photo`, where the letterform is rendered in `{colors.accent}`.
- **Every 1px structural border uses `{colors.line}`.** Other border colors do not exist except for the rare `horizontal-accent` rule in ink.
- **Every card, image-placeholder, team-photo, and nav-arrow border is 1px solid.** Thicker borders do not exist in this system.
- **Charts use ink-black for the primary series and dashed taupe (5px, 5px) for the comparison series.** This pair is the only chart-color rule.

### Typography Principles
The Playfair-400 + Inter-400 combination is the system's voice. Switching either family or jumping Playfair to weight 700 reads as a different design system. Italic emphasis is permitted via inline `<em>` inside body copy (Inter italic) — italic Playfair is loaded but reserved for rare uses. Underline is not used.

Line-height stays open: headlines at 1.1, body at 1.6. The wide body line-height is part of the breathing-room aesthetic.

## Layout

### Canvas System
The canvas is `100vw × 100vh` — full viewport with hidden overflow. Each `.slide` is absolutely positioned to fill the viewport; one slide carries `.active` (opacity 1, visibility visible) at a time. Transitions are 0.6s opacity + visibility fades.

### Padding and Gap Scale
| Token | Value | Use |
|---|---|---|
| `{spacing.pad-y}` | 4vh | Default vertical slide padding |
| `{spacing.pad-x}` | 4vw | Default horizontal slide padding |
| `{spacing.gap-xl}` | 6vw | Major two-column gutter (most spacious) |
| `{spacing.gap-lg}` | 5vw | Standard two-column or grid gutter |
| `{spacing.gap-md}` | 3vw | Card-grid gutter |
| `{spacing.gap-sm}` | 2vh | Agenda row vertical padding, attribution spacing |
| `{spacing.card-pad}` | 4vh 2vw | Internal padding for content cards |

Headlines typically carry a 2–3vh margin-bottom from labels above and a 2vh margin-bottom from body below. Section headers above 3-card or 4-team grids carry a 6vh margin-bottom from the grid (significant breathing room).

### Decorative Geometry Layer
Cartesian's signature is its **drafting-paper geometric decoration**. Every slide may layer one or more of:
- A large ringed `geo-decoration` anchored to a corner (typically 30–50vw diameter) with an inner dashed ring at ~80% diameter (the `::before` pseudo).
- A `vertical-line` at ~8vw from the left edge running floor-to-ceiling at 30% opacity.
- A `horizontal-accent` (a single short black 1px line) anchored at 15vh from the bottom-left.
- A centered `geo-ring` (50vw circle) on closing or contemplative slides.

These elements have **no informational role** — they create atmosphere. Slides without any geometric decoration are valid; over-decoration (more than two geo elements per slide) breaks the restraint.

### Chrome
The system's chrome is minimal:
- Right-edge vertical column of small `nav-dot` indicators (8px circles in taupe).
- Bottom-left pair of square `nav-arrow` buttons (40×40, 1px taupe border, transparent fill).
- Bottom-right `slide-counter` text in Inter at 0.75rem with 2px tracking in `{colors.accent}`.

There is no top chrome bar, no persistent header, no footer rule.

## Depth and Elevation

### Flat Plane (Only Technique)
Cartesian has no shadows, no elevated cards, no rounded surfaces, no gradients. Every element sits on a single plane.

Hierarchy is constructed from:
- **Type contrast** — Playfair serif vs Inter sans; size scale from 5rem down to 0.7rem.
- **1px hairline dividers** — agenda rows, timeline rule, card outlines, image-placeholder outlines, stats top-border, team-photo rings, nav-arrow borders.
- **Color tone** — ink vs gray vs taupe.
- **Negative space** — generous padding around every element.
- **Geometric atmosphere** — compass-drafted rings behind content suggest depth without creating it.

Introducing a `box-shadow`, an elevated card, or a soft gradient breaks the restraint that defines the system.

## Shapes and Treatment

### Border Radius
| Value | Use |
|---|---|
| 50% (circle) | Every circular element: `card-icon` (40px), `team-photo` (12vw), `nav-dot` (8px), `geo-circle`, `geo-arc`, `geo-decoration`, `geo-ring` |
| 0 | Everything else: cards, image-placeholders, nav-arrows, agenda rows, timeline, stat-blocks, chart container |

The system uses **only two radius values**: 50% (true circle) or 0 (sharp rectangle). Soft-rounded corners do not exist.

### Border Weights
- **1px solid `{colors.line}`** — the universal structural border. Used on every card, image-placeholder, team-photo ring, nav-arrow, agenda row bottom, timeline rule, stats top, geo-circle, geo-decoration.
- **1px dashed `{colors.line}`** — used on `geo-arc` and the inner `::before` ring inside `geo-decoration` / `geo-ring`. Dashed signals "construction line / arc."
- **1px solid `{colors.text-primary}`** — used only on the rare `horizontal-accent` decorative rule. The system's only ink-black line.
- **Chart bar/line stroke widths** — Chart.js series at 1px (bar borders), 2px (line series). Comparison series at 2px dashed (5px dash, 5px gap).

All structural borders are `{colors.line}`. Thicker borders, colored borders, and dashed structural borders (other than geo-arcs) do not exist.

### Decorative Element Types

**Geometric ring (geo-circle / geo-decoration / geo-ring)** — Thin 1px taupe circles in various sizes (10vw, 30vw, 50vw) at 20–50% opacity. Typically paired with an inner dashed `::before` ring at 70–80% of the outer diameter, suggesting compass construction with both a primary and an offset arc. Anchored to corners or centers; sits behind content with `z-index: 0` and `pointer-events: none`.

**Vertical line** — A single 1px taupe column anchored at ~8vw from the left slide edge, running floor-to-ceiling at 30% opacity. Suggests a drafting-paper alignment guide. Optional per slide.

**Horizontal accent** — A single 20vw × 1px black line anchored 15vh from the bottom-left of a slide. The system's only ink-black line — used as a strong terminal accent rule on cover or closing layouts. Use sparingly.

**Image placeholder** — A solid `{colors.bg-secondary}` block with two 150% diagonal 1px taupe lines crossed at +30° and -30° via `::before` / `::after`, forming an X. Centers a small uppercase Inter label ("Visual Reference" or similar). The X pattern is the signature image-not-yet-wired treatment.

**Team-photo frame** — A 12vw circular block in `{colors.bg-secondary}` with a 1px taupe ring, holding a single Playfair-400 initial at 2rem in `{colors.accent}` centered. Used as portrait placeholder.

**Card** — A 1px taupe-bordered block with a semi-transparent white interior fill (`{colors.white-overlay}`) that lets the canvas tone bleed through subtly. The faint white fill is what differentiates a card from a bare region; remove the fill and the card disappears.

**Agenda row** — A flex row containing a Playfair `{typography.agenda-numeral}` in `{colors.accent}` at left, then a label at right, with 2vh padding and a 1px taupe bottom border. Stacked rows form an agenda list.

**Timeline** — A 1px taupe top-border across a flex row of evenly-distributed timeline items; each item carries a small Inter `year` label in taupe, a Playfair `{typography.timeline-headline}`, and an Inter body paragraph. The hairline is the only timeline structure — there are no nodes, no markers, no dots.

**Stats cluster** — A flex row of stat items separated by `gap-md`, framed by a 1px taupe top border, holding inline `{typography.stat-figure}` Playfair numerals with small uppercase Inter labels in taupe below.

**Quote mark** — A 5rem Playfair quote glyph at 50% opacity in taupe, positioned above a Playfair `{typography.h2}` headline + a small uppercase taupe attribution below.

**Chart** — Chart.js bar or line chart with ink-black primary series and dashed taupe comparison series. Grid lines in `{colors.bg-secondary}`. Axis ticks in `{colors.accent}`. Always rendered without fill on the primary series (or with a 5% ink-tinted fill on line charts).

## Do's and Don'ts

### Do
- Use a single 1px line in `{colors.line}` for every structural separator — agenda rule, timeline connector, card border, stats top, team-photo ring. The 1px hairline is Cartesian's identity.
- Set every Playfair headline, stat, quote mark, and card title at weight 400. Don't reach for bold; the thin-stroke didone aesthetic depends on it.
- Render every headline in `{colors.text-primary}` (ink). Playfair never appears in taupe or color.
- Render every label, attribution, agenda numeral, and micro-text in `{colors.accent}` (taupe) with uppercase + 2–3px letter-spacing.
- Layer decorative geometric rings (solid + dashed) at 20–50% opacity behind content for atmosphere. One or two geo elements per slide; never more.
- Pair Playfair Display (serif headlines) with Inter (sans body). The two-face pairing is fixed.
- Use the crossed-diagonal X pattern inside image placeholders. It is the system's signature placeholder treatment.
- Let slides breathe — sparse layouts with generous negative space are the correct density.
- Use `{colors.bg-secondary}` as the fill for image placeholders and team-photo frames — a subtle stone, not white, not gray.
- Use a single `horizontal-accent` (20vw × 1px ink line) sparingly as a strong terminal rule on cover or closing compositions.

### Don't
- Don't introduce a populist accent color. No red, no orange, no blue, no green. The palette is stone-on-stone with ink for headlines.
- Don't render Playfair headlines in `{colors.accent}` (taupe). Headlines are ink; taupe is reserved for small text.
- Don't bold any Playfair element. Weight 400 is the standing rule; bold breaks the didone aesthetic.
- Don't add shadows, elevated cards, or gradient fills. Cartesian is flat; depth comes from geometry and type, not z-axis.
- Don't use rounded corners on cards or rectangles. The only round shapes are true circles (radius 50%).
- Don't use thick borders (2px+). Every structural border is 1px.
- Don't crowd the slide. Sparse breathing layouts read as elegant; packed layouts read as broken.
- Don't pair Playfair with a different sans companion. The Inter pairing is fixed.
- Don't render labels or micro-text in sentence case. Small Inter text is always uppercase + 2–3px tracking.
- Don't add more than two geo decorations per slide — restraint is the rule; over-decoration reads as cluttered.

## Responsive Behavior

Cartesian is a viewport-fluid 1920×1080 presentation system using `vw` / `vh` units and `clamp()` throughout. There is a single `@media (max-aspect-ratio: 4/3)` breakpoint that collapses two-column grids to single-column, hides the timeline rule (which would lose meaning when stacked), and stacks team and card grids vertically. The system is otherwise responsive without breakpoints.

### Scaling Behavior
- Display headlines scale from 2.5rem at minimum viewport to 5.5rem at maximum via `clamp()`.
- Body text scales from 0.9rem to 1.1rem.
- Padding uses `vh` / `vw` units that scale linearly with viewport.
- The 1px borders, 8px nav dots, and 40px nav arrows are fixed and do not scale.

### Presenter Behavior
- Slides advance via `ArrowRight` or `Space`.
- Slides reverse via `ArrowLeft`.
- Nav dots at right edge can be clicked to jump to specific slides.
- Nav arrows at bottom-left are clickable; hover state inverts background to ink and text to cream.
- Slide counter at bottom-right shows current / total with 2-digit zero-padding.

### Charts
Charts are rendered with Chart.js (loaded via CDN). The two chart types in the source are bar and line; both follow the ink-primary / dashed-taupe-comparison convention. Custom font settings inject Inter into Chart.js label rendering.

### Print / Export
Not explicitly handled. Each slide is a 100vw × 100vh block; export workflows should snapshot each slide at 1920×1080.

## CJK & International Content

### Recommended Chinese Pairing

| Role | Latin font | Recommended Chinese pairing | Source |
|---|---|---|---|
| Display / Headline (Playfair Display 400) | Playfair Display | 思源宋体 Noto Serif SC 700 | Google Fonts |
| Body / Label (Inter 400–500) | Inter | 思源宋体 Noto Serif SC 400 | Google Fonts |

### Mixed-Content Strategy

Use **Strategy A — single-font-stack with fallback**: declare Noto Serif SC *after* the Latin font in the same `font-family` stack so Latin glyphs render in Playfair / Inter and CJK glyphs fall through to Noto Serif SC automatically. One CSS rule per role, no manual class switching.

### Loading

```html
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400..700;1,400..700&family=Inter:wght@300..600&family=Noto+Serif+SC:wght@400;700&display=swap" rel="stylesheet">
```

```css
:root {
  --font-display: "Playfair Display", "Noto Serif SC", serif;
  --font-body: "Inter", "Noto Serif SC", sans-serif;
}
/* Headlines use Noto Serif SC 700; body uses Noto Serif SC 400. */
```

### Universal CJK Adjustments

- **Line-height**: bump CJK body line-height to ~1.75 (from 1.6) — Hanzi need more vertical breathing than Latin lowercase, and Cartesian already favors generous leading.
- **Letter-spacing**: zero out `letter-spacing` on Hanzi runs. Keep the 2–3px tracking only on uppercase Latin labels.
- **Text-transform**: drop `text-transform: uppercase` on any label/attribution/micro when content is Hanzi — Chinese has no case; forcing uppercase does nothing for Hanzi but breaks the rendering of any mixed Latin acronyms inside.
- **Punctuation**: use Chinese full-width punctuation (，。：；「」) for Chinese sentences, half-width (`,.:;""`) for Latin. Never mix half-width punctuation into a Chinese sentence.
- **No period on headlines**: Chinese headline convention omits the terminal 。 — strip it from display strings.
- **Pangu spacing**: insert a thin space (or a regular space) between adjacent Hanzi and Latin/digit runs (e.g. `2026 年`, `AI 产品`). Improves readability of mixed runs.
- **One font per sentence**: don't switch CJK families mid-sentence. Pick a single weight of Noto Serif SC for a given text run, never two inside one phrase.

### Aesthetic Notes

Noto Serif SC (思源宋体) is the only mainstream Hanzi serif with the same restrained editorial register Cartesian needs — its modulated horizontal-thin / vertical-thick strokes echo Playfair's didone aesthetic, and its uniformly even cadence matches Cartesian's "museum-catalog" voice. Using NSC at weight 700 for headlines preserves the visual mass of the Latin display while NSC 400 carries body with the same quiet warmth Inter provides. The five-stone palette absorbs Hanzi cleanly because every glyph stays in ink or taupe — no candy fills to negotiate. The decorative compass-arc geometry layer is content-agnostic and works identically in any language. Avoid bolding Hanzi (the Chinese-typography equivalent of Cartesian's "no bold Playfair" rule); rely on size and the 1px line dividers for hierarchy.

### Known CJK Gap

Noto Serif SC is the only Hanzi serif loaded — there is no italic axis (Chinese type historically has no italic), so the rare italic Playfair `<em>` moment loses its emphasis when the body falls through to NSC. Substitute a single-character span colored in `{colors.accent}` (taupe), or wrap the emphasized phrase in faint brackets 「」, to recover emphasis. NSC's 700 weight is the heaviest available — the system's restraint-through-400-weight rule naturally extends to Chinese, so this is rarely a gap in practice.

## Iteration Guide

1. Every new structural separator uses a 1px solid `{colors.line}` border. No exceptions.
2. Every new headline uses Playfair Display at weight 400 in `{colors.text-primary}`. Don't bold; don't color.
3. Every new small text element (label, attribution, micro) uses Inter uppercase with 2–3px letter-spacing in `{colors.accent}`.
4. Every new body paragraph uses Inter weight 400 in `{colors.text-secondary}`, with line-height 1.6.
5. Every new card uses 1px taupe border + semi-transparent white overlay fill. No shadow, no radius.
6. New circular elements (icons, photos, decorative rings) use border-radius 50% with 1px taupe ring.
7. New geometric decorations stay subtle: 1 or 2 per slide, at 20–50% opacity, behind content (z-index 0, pointer-events none).
8. New chart series follow the ink-primary / dashed-taupe-comparison convention. Don't introduce colored chart series.
9. New layouts respect the breathing-room density rule — sparse beats dense in Cartesian.
10. The `horizontal-accent` 20vw ink line is the system's only "ink rule" — use it sparingly as a terminal accent, never as a routine divider.

## Known Gaps

- The Chart.js library is loaded via CDN; new chart types beyond bar and line require manual configuration matching the ink-primary / dashed-taupe-comparison aesthetic.
- The decorative `geo-decoration` and `geo-ring` `::before` inner-ring pattern is hardcoded in CSS; size variants beyond what the source exercises require new style rules.
- The team-photo placeholder shows a single Playfair initial in taupe; real portrait insertion requires replacing the initial with an `<img>` and adjusting the circular crop.
- The chart axis label colors and grid colors are hardcoded inline in the Chart.js options blocks (rather than reading from CSS variables) — restyling requires editing JS, not CSS.
- The image-placeholder X pattern (crossed +30°/-30° diagonals) is rendered via `::before` / `::after` with fixed 150% widths; resizing the placeholder beyond the source dimensions may require recomputing the rotation angle to maintain edge-touch.
- Italic Playfair is loaded but not exercised in any default rule; it is available for inline `<em>` emphasis in body copy but the system itself does not author any italic text.
- The `vertical-line` and `horizontal-accent` decorative elements have hardcoded position values (8vw from left, 15vh from bottom); using them off-default-position requires per-instance style overrides.
- The slide-counter `currentSlide` / `totalSlides` IDs are referenced in the JS but the system has no internal slide-name registry; new slides simply increment by their DOM order.
````

---

## 2. 글씨체

- 이 디자인의 한글 글씨체: 제목 Cafe24 Oneprettynight(400) · 본문 프리텐다드 Pretendard-Light(300). (쓰는 폰트: Cafe24 Oneprettynight, 프리텐다드 Pretendard-Light)
- 글씨체 파일은 공통 CSS(5)의 `@font-face`가 인터넷의 폰트 창고(`https://maker-ssam.github.io/korean-ofl-fonts/…`)에서 불러옵니다. 설치하지 않아도 되지만 열 때 인터넷이 필요합니다.
- 글씨체 규칙(굵기·크기·자간)은 1의 디자인 규칙을 따르고, 한글 폰트는 변수(`--kt` 제목, `--kb` 본문, `--ka` 포인트)로만 지정하세요.

---

## 3. 부품 사전 (이 디자인의 CSS에 정의된 클래스)

이 목록과 공통 CSS(5)에 있는 클래스만 쓰세요. '○장'은 아래 뼈대에서 그 클래스를 쓴 예시 장이고, '예'는 그 장의 실제 태그입니다. 장 구성은 따라 하지 말고, 필요한 부품을 골라 어느 장에서든 쓰면 됩니다. 클래스를 조합하는 방법(어떤 부품 안에 어떤 부품이 들어가는지)은 뼈대의 예시 장을 보고 따르세요.
- 여러 장에서 쓰인 클래스는 이 디자인의 공통 부품입니다(창·제목줄·버튼·표 등).
- 한 장에서만 쓰인 클래스 중 크기·위치를 정하는 것(이름에 번호가 붙은 창·격자 등)은 **그 예시 장 전용 배치**입니다. 같은 배치를 다시 쓸 때만 쓰고, 새 배치가 필요하면 비슷한 이름을 지어 쓰지 말고 '추가 부품' 칸에 직접 정의하세요.
- 예시 장의 측정기 그림(`g-…` 클래스)은 예시 주제 전용이라 이 목록에 없습니다. 새 주제의 그림은 SVG로 새로 그리세요.

**1장(표지)에서 처음 나오는 부품**
- `.bl` — 1·5장 — 예: `<div class="lab bl">`
- `.br` — 1장 — 예: `<div class="lab br">`
- `.geo` — 1·2·3·4·5·6장 — 예: `<div class="geo big" style="right:-300px;top:50%;margin-top:-520px;width:1040px;height:1040px">`
- `.gk` — 1장 — 예: `<em class="gk">`
- `.gl` — 1·3장 — 예: `<div class="lab gl">`
- `.haccent` — 1·5장 — 예: `<i class="haccent">`
- `.lab` — 1·2·3·4·5·6장 — 예: `<div class="lab tl">`
- `.slide` — 1·2·3·4·5·6장 — 예: `<section class="slide">`
- `.t1` — 1장 — 예: `<h1 class="t1">`
- `.tl` — 1·2·3·4·5·6장 — 예: `<div class="lab tl">`
- `.tr` — 1·4장 — 예: `<div class="lab tr">`
- `.unit` — 1장 — 예: `<p class="unit">`
- `.vline` — 1·2·3·4·5·6장 — 예: `<i class="vline">`

**2장(흐름·단계)에서 처음 나오는 부품**
- `.agenda` — 2·6장 — 예: `<div class="agenda">`
- `.an` — 2·4·5·6장 — 예: `<span class="an">`
- `.arow` — 2·4·6장 — 예: `<div class="arow" data-s="1">`
- `.btns` — 2·5장 — 예: `<div class="btns">`
- `.cap` — 2장 — 예: `<p class="cap" data-caps="[&quot;버튼을 눌러 순서대로 만들어 보세요&quot;,&quot;01 — 자 붙이기&quot;,&quot;02 — 수수깡 꽂기&quot;,&quo…`
- `.card` — 2·4·5·6장 — 예: `<div class="card fig">`
- `.def` — 2장 — 예: `<p class="def">`
- `.fig` — 2장 — 예: `<div class="card fig">`
- `.fnote` — 2장 — 예: `<p class="fnote">`
- `.hd` — 2·3·4·5·6장 — 예: `<h2 class="hd">`
- `.mic` — 2·6장 — 예: `<span class="mic">`
- `.nr` — 2·4·5·6장 — 예: `<p class="nr">`
- `.side` — 2장 — 예: `<div class="side">`
- `.sq` — 2·5·6장 — 예: `<button class="sq" data-act="step">`

**3장(숫자와 그래프)에서 처음 나오는 부품**
- `.ax` — 3장 — 예: `<text x="76" y="328" class="ax" text-anchor="end">`
- `.base` — 3장 — 예: `<line x1="90" x2="1560" y1="320" y2="320" class="base"/>`
- `.bn` — 3장 — 예: `<i class="k bn">`
- `.bv` — 3장 — 예: `<text x="195" y="215.4" class="bv" text-anchor="middle">`
- `.chartw` — 3장 — 예: `<div class="chartw">`
- `.cv` — 3장 — 예: `<svg class="cv" viewBox="0 0 1660 380">`
- `.k` — 3장 — 예: `<i class="k bn">`
- `.lg` — 3장 — 예: `<div class="lg">`
- `.ls` — 3장 — 예: `<i class="k ls">`
- `.lsp` — 3장 — 예: `<circle cx="195" cy="224.54" r="5" class="lsp"/>`
- `.lt` — 3장 — 예: `<i class="k lt">`
- `.ltp` — 3장 — 예: `<circle cx="195" cy="142.4" r="5" class="ltp"/>`
- `.pv` — 3장 — 예: `<text x="241" y="232.54" class="pv">`
- `.sf` — 3장 — 예: `<b class="sf">`
- `.src` — 3장 — 예: `<p class="src">`
- `.st` — 3장 — 예: `<div class="st">`
- `.stats` — 3장 — 예: `<div class="stats">`

**4장(비교와 표)에서 처음 나오는 부품**
- `.cc` — 4장 — 예: `<div class="card cc">`
- `.cmp` — 4장 — 예: `<div class="cmp">`
- `.icon` — 4장 — 예: `<span class="icon">`
- `.lst` — 4장 — 예: `<div class="lst">`
- `.qm` — 4장 — 예: `<span class="qm">`
- `.qt` — 4장 — 예: `<blockquote class="qt">`
- `.sm` — 4·6장 — 예: `<div class="arow sm">`
- `.tbl` — 4장 — 예: `<div class="tbl">`
- `.th` — 4장 — 예: `<div class="tr th">`

**5장(확인(퀴즈·빈칸))에서 처음 나오는 부품**
- `.blank` — 5장 — 예: `<button class="blank" data-blank aria-pressed="false">`
- `.blk` — 5장 — 예: `<div class="card blk">`
- `.end` — 5장 — 예: `<i class="haccent end">`
- `.fb` — 5장 — 예: `<p class="fb" data-fb>`
- `.ot` — 5장 — 예: `<span class="ot">`
- `.q` — 5장 — 예: `<h3 class="q">`
- `.quiz` — 5장 — 예: `<div class="card quiz" data-quiz data-answer="1" data-right="정답! 태양 고도가 가장 높을 때(남중) 그림자가 가장 짧아요" data-wrong="다…`
- `.row` — 5장 — 예: `<button class="row" data-opt="0">`
- `.rows` — 5장 — 예: `<div class="rows">`
- `.wl` — 5장 — 예: `<span class="lab wl">`
- `.words` — 5장 — 예: `<p class="words">`

**6장(디자인 안내(시연))에서 처음 나오는 부품**
- `.a` — 6장 — 예: `<div class="card d6 a">`
- `.b` — 6장 — 예: `<div class="card d6 b">`
- `.c` — 6장 — 예: `<div class="card d6 c">`
- `.d6` — 6장 — 예: `<div class="card d6 a">`
- `.dh` — 6장 — 예: `<div class="dh">`
- `.dr` — 6장 — 예: `<div class="dr">`
- `.g` — 6장 — 예: `<path class="g" d="M0 35H560M0 68H560"/>`
- `.g6` — 6장 — 예: `<div class="agenda g6">`
- `.geo6` — 6장 — 예: `<i class="geo6">`
- `.ln6` — 6장 — 예: `<svg class="ln6" id="ct-ln" viewBox="0 0 560 70">`
- `.m` — 6장 — 예: `<polyline class="m" points="10,60 90,40 170,22 250,14 330,24 410,40 490,62"/>`
- `.s` — 6장 — 예: `<polyline class="s" points="10,50 90,42 170,32 250,26 330,22 410,20 490,24"/>`
- `.sl6` — 6장 — 예: `<div class="lab sl6">`
- `.sw6` — 6장 — 예: `<span class="sw6">`
- `.tr6` — 6장 — 예: `<div class="tr6" id="ct-tr">`
- `.trc` — 6장 — 예: `<div class="dr trc">`

**예시 장에는 없지만 CSS에 정의된 클래스**(디자인 규칙에 맞으면 써도 됨): `.nb`

**직접 쓰지 말 것**: 엔진이 상태를 나타내려고 붙이는 클래스(`.on` `.now` `.open` `.right` `.wrong` `.play` `.solved` `.tried` `.active` `.visible` `.flash` `.in-frame`)와 내비 클래스(`.dk-…`)는 배치용으로 쓰지 마세요(뼈대의 내비 부분은 그대로 둡니다).

---

## 4. HTML 뼈대 (예시 덱 6장 — 부품 견본입니다. 장 구성은 따라 하지 말고, 공통 파일 두 줄은 그대로 두며, 장은 내용에 맞게 새로 구성)

```html
<!DOCTYPE html>
<html lang="ko" data-template="cartesian">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>계절의 변화</title>
<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;1,400&family=Inter:wght@400;500&display=swap">
<!-- 이 디자인의 공통 CSS(글씨체·색·부품 모양). 이 줄은 지우거나 바꾸지 마세요 -->
<link rel="stylesheet" href="https://k-slide.web.app/kit/v1/cartesian.css">
<style>
/* === 추가 부품: 새 클래스가 꼭 필요할 때만 이 줄 아래에 정의하세요(공통 CSS는 위 <link>가 이미 불러옴 — 여기에 옮겨 쓰지 않음) === */
</style>
</head>
<body>
<div class="deck-viewport">
  <main class="deck-stage" id="deckStage">
<section class="slide">
  <i class="vline"></i>
  <div class="geo big" style="right:-300px;top:50%;margin-top:-520px;width:1040px;height:1040px"></div>
  <div class="lab tl">초등 과학 · 6학년 2학기</div><div class="lab tr">1단원 · 3~4차시</div>
  <p class="unit">계절의 변화<span>Sun, Shadow & Temperature</span></p>
  <div class="lab gl">학습 목표</div>
  <h1 class="t1">하루 동안 <em class="gk">태양 고도</em>,<br><em class="gk">그림자 길이</em>, <em class="gk">기온</em>의 관계</h1>
  <i class="haccent"></i>
  <div class="lab bl">00초등학교</div><div class="lab br">2026</div>
</section>
<section class="slide" data-steps="4">
  <i class="vline"></i>
  <div class="geo mid" style="right:-140px;top:-220px;width:620px;height:620px"></div>
  <div class="lab tl">측정 준비</div>
  <h2 class="hd">태양 고도 측정기 만들기</h2>
  <div class="card fig"><span class="mic">태양 고도 측정기</span><svg class="gauge" viewBox="0 0 1000 660" role="img" aria-label="태양 고도 측정기: 태양 빛, 수수깡, 실, 태양 고도, 그림자 길이, 자, 각도기">
  <line class="g-ground" x1="20" x2="980" y1="580" y2="580"/>
  <rect class="g-board" x="80" y="540" width="860" height="40"/>
  <g class="g-part" data-s="1"><rect class="g-ruler" x="110" y="524" width="800" height="16"/><line class="g-tick" x1="120" x2="120" y1="524" y2="536"/><line class="g-tick" x1="140" x2="140" y1="524" y2="530"/><line class="g-tick" x1="160" x2="160" y1="524" y2="530"/><line class="g-tick" x1="180" x2="180" y1="524" y2="530"/><line class="g-tick" x1="200" x2="200" y1="524" y2="530"/><line class="g-tick" x1="220" x2="220" y1="524" y2="536"/><line class="g-tick" x1="240" x2="240" y1="524" y2="530"/><line class="g-tick" x1="260" x2="260" y1="524" y2="530"/><line class="g-tick" x1="280" x2="280" y1="524" y2="530"/><line class="g-tick" x1="300" x2="300" y1="524" y2="530"/><line class="g-tick" x1="320" x2="320" y1="524" y2="536"/><line class="g-tick" x1="340" x2="340" y1="524" y2="530"/><line class="g-tick" x1="360" x2="360" y1="524" y2="530"/><line class="g-tick" x1="380" x2="380" y1="524" y2="530"/><line class="g-tick" x1="400" x2="400" y1="524" y2="530"/><line class="g-tick" x1="420" x2="420" y1="524" y2="536"/><line class="g-tick" x1="440" x2="440" y1="524" y2="530"/><line class="g-tick" x1="460" x2="460" y1="524" y2="530"/><line class="g-tick" x1="480" x2="480" y1="524" y2="530"/><line class="g-tick" x1="500" x2="500" y1="524" y2="530"/><line class="g-tick" x1="520" x2="520" y1="524" y2="536"/><line class="g-tick" x1="540" x2="540" y1="524" y2="530"/><line class="g-tick" x1="560" x2="560" y1="524" y2="530"/><line class="g-tick" x1="580" x2="580" y1="524" y2="530"/><line class="g-tick" x1="600" x2="600" y1="524" y2="530"/><line class="g-tick" x1="620" x2="620" y1="524" y2="536"/><line class="g-tick" x1="640" x2="640" y1="524" y2="530"/><line class="g-tick" x1="660" x2="660" y1="524" y2="530"/><line class="g-tick" x1="680" x2="680" y1="524" y2="530"/><line class="g-tick" x1="700" x2="700" y1="524" y2="530"/><line class="g-tick" x1="720" x2="720" y1="524" y2="536"/><line class="g-tick" x1="740" x2="740" y1="524" y2="530"/><line class="g-tick" x1="760" x2="760" y1="524" y2="530"/><line class="g-tick" x1="780" x2="780" y1="524" y2="530"/><line class="g-tick" x1="800" x2="800" y1="524" y2="530"/><line class="g-tick" x1="820" x2="820" y1="524" y2="536"/><line class="g-tick" x1="840" x2="840" y1="524" y2="530"/><line class="g-tick" x1="860" x2="860" y1="524" y2="530"/><line class="g-tick" x1="880" x2="880" y1="524" y2="530"/><line class="g-tick" x1="900" x2="900" y1="524" y2="530"/><text class="g-lb" x="922" y="516" text-anchor="start">자</text></g>
  <g class="g-meas"><rect class="g-shadow" x="220" y="524" width="446" height="16"/>
    <path class="g-dim" d="M220 600v24M666 600v24M220 612H666"/><text class="g-lb" x="443" y="652" text-anchor="middle">그림자 길이</text></g>
  <g class="g-part" data-s="2"><rect class="g-stick" x="196" y="150" width="24" height="374"/><path class="g-mark" d="M220 504h20v20"/>
    <path class="g-lead" d="M182 330H196"/><text class="g-lb" x="174" y="342" text-anchor="end">수수깡</text></g>
  <g class="g-part" data-s="4"><path class="g-prot" d="M546 524A120 120 0 0 1 786 524Z"/><path class="g-prot2" d="M588 524A78 78 0 0 1 744 524"/><line class="g-tick" x1="570" y1="524" x2="546" y2="524"/><line class="g-tick" x1="561.6" y1="505.6" x2="547.8" y2="503.2"/><line class="g-tick" x1="566.4" y1="487.7" x2="553.2" y2="483"/><line class="g-tick" x1="582.9" y1="476" x2="562.1" y2="464"/><line class="g-tick" x1="584.8" y1="455.9" x2="574.1" y2="446.9"/><line class="g-tick" x1="597.9" y1="442.8" x2="588.9" y2="432.1"/><line class="g-tick" x1="618" y1="440.9" x2="606" y2="420.1"/><line class="g-tick" x1="629.7" y1="424.4" x2="625" y2="411.2"/><line class="g-tick" x1="647.6" y1="419.6" x2="645.2" y2="405.8"/><line class="g-tick" x1="666" y1="428" x2="666" y2="404"/><line class="g-tick" x1="684.4" y1="419.6" x2="686.8" y2="405.8"/><line class="g-tick" x1="702.3" y1="424.4" x2="707" y2="411.2"/><line class="g-tick" x1="714" y1="440.9" x2="726" y2="420.1"/><line class="g-tick" x1="734.1" y1="442.8" x2="743.1" y2="432.1"/><line class="g-tick" x1="747.2" y1="455.9" x2="757.9" y2="446.9"/><line class="g-tick" x1="749.1" y1="476" x2="769.9" y2="464"/><line class="g-tick" x1="765.6" y1="487.7" x2="778.8" y2="483"/><line class="g-tick" x1="770.4" y1="505.6" x2="784.2" y2="503.2"/><line class="g-tick" x1="762" y1="524" x2="786" y2="524"/><circle class="g-hole" cx="666" cy="524" r="5"/><text class="g-lb" x="800" y="456" text-anchor="start">각도기</text></g>
  <g class="g-part" data-s="3"><line class="g-string" x1="220" y1="150" x2="666" y2="524"/><text class="g-lb" x="478" y="344" text-anchor="start">실</text></g>
  <g class="g-meas"><path class="g-angle" d="M616 524A50 50 0 0 1 627.7 491.9"/><path class="g-lead" d="M542 498L615 506.9"/><text class="g-lb" x="536" y="508" text-anchor="end">태양 고도</text>
    <line class="g-ray" x1="74.5" y1="27.9" x2="187.8" y2="123"/><polygon class="g-rayh" points="209.3,141 179.5,133 196.2,113"/><text class="g-lb" x="150" y="60" text-anchor="start">태양 빛</text></g>
</svg></div>
  <p class="fnote">막대기의 그림자와 실이 이루는 각 = 태양 고도</p>
  <div class="side">
    <p class="def">태양 고도 — 태양이 지표면과 이루는 각</p>
    <div class="agenda"><div class="arow" data-s="1"><span class="an">I</span><div><h3>자 붙이기</h3><p>우드록 한쪽에 양면테이프로 자를 붙여요</p></div></div><div class="arow" data-s="2"><span class="an">II</span><div><h3>수수깡 꽂기</h3><p>수수깡을 10cm 정도 잘라 자의 '0' 위치에 수직으로 꽂아요</p></div></div><div class="arow" data-s="3"><span class="an">III</span><div><h3>실 묶기</h3><p>수수깡 끝에 실을 묶어요</p></div></div><div class="arow" data-s="4"><span class="an">IV</span><div><h3>각도기 끼우기</h3><p>실의 다른 끝을 각도기 가운데 구멍에 끼워요</p></div></div></div>
    <div class="btns"><button class="sq" data-act="step">다음 단계 →</button><button class="sq" data-act="reset">처음부터</button></div>
    <p class="cap" data-caps="[&quot;버튼을 눌러 순서대로 만들어 보세요&quot;,&quot;01 — 자 붙이기&quot;,&quot;02 — 수수깡 꽂기&quot;,&quot;03 — 실 묶기&quot;,&quot;04 — 각도기 끼우기&quot;]">버튼을 눌러 순서대로 만들어 보세요</p>
  </div>
  <p class="nr">버튼 규칙 없음 → 사각 화살표 단추 모양으로 표현</p>
</section>
<section class="slide">
  <i class="vline"></i>
  <div class="geo small" style="left:1500px;top:-160px;width:520px;height:520px"></div>
  <div class="lab tl">측정 결과</div>
  <h2 class="hd">하루 동안 무엇이 어떻게 변할까요?</h2>
  <div class="stats"><div class="st"><b class="sf">12:30</b><span class="lab">남중 시각</span><p>태양 고도가 가장 높아요 무렵 · 남중</p></div><div class="st"><b class="sf">정남</b><span class="lab">남중 방향</span><p>남중할 때 태양의 위치 쪽</p></div><div class="st"><b class="sf">14:30</b><span class="lab">최고 기온</span><p>기온이 가장 높아요 무렵</p></div><div class="st"><b class="sf">9:30</b><span class="lab">가장 긴 그림자</span><p>그림자가 가장 길어요 · 15:30</p></div></div>
  <div class="chartw">
    <div class="lg"><span class="lab">측정 시각별 태양 고도, 그림자 길이, 기온 · 예시 값</span><span><i class="k bn"></i>태양 고도(°)</span><span><i class="k ls"></i>그림자 길이(cm)</span><span><i class="k lt"></i>기온(℃)</span></div>
    <svg class="cv" viewBox="0 0 1660 380"><line x1="90" x2="1560" y1="320" y2="320" class="gl"/><text x="76" y="328" class="ax" text-anchor="end">0°</text><line x1="90" x2="1560" y1="246" y2="246" class="gl"/><text x="76" y="254" class="ax" text-anchor="end">20°</text><line x1="90" x2="1560" y1="172" y2="172" class="gl"/><text x="76" y="180" class="ax" text-anchor="end">40°</text><line x1="90" x2="1560" y1="98" y2="98" class="gl"/><text x="76" y="106" class="ax" text-anchor="end">60°</text><line x1="90" x2="1560" y1="24" y2="24" class="gl"/><text x="76" y="32" class="ax" text-anchor="end">80°</text><text x="1576" y="328" class="ax">10℃</text><text x="1576" y="180" class="ax">20℃</text><text x="1576" y="32" class="ax">30℃</text><rect x="155" y="179.4" width="80" height="140.6" class="bn"/><text x="195" y="215.4" class="bv" text-anchor="middle">38°</text><rect x="365" y="142.4" width="80" height="177.6" class="bn"/><text x="405" y="178.4" class="bv" text-anchor="middle">48°</text><rect x="575" y="116.5" width="80" height="203.5" class="bn"/><text x="615" y="152.5" class="bv" text-anchor="middle">55°</text><rect x="785" y="109.1" width="80" height="210.9" class="bn"/><text x="825" y="145.1" class="bv" text-anchor="middle">57°</text><rect x="995" y="120.19999999999999" width="80" height="199.8" class="bn"/><text x="1035" y="156.2" class="bv" text-anchor="middle">54°</text><rect x="1205" y="146.1" width="80" height="173.9" class="bn"/><text x="1245" y="182.1" class="bv" text-anchor="middle">47°</text><rect x="1415" y="183.1" width="80" height="136.9" class="bn"/><text x="1455" y="219.1" class="bv" text-anchor="middle">37°</text><polyline class="ls" points="195,224.54 405,252.66 615,268.2 825,272.64 1035,266.71999999999997 1245,250.44 1455,220.84"/><circle cx="195" cy="224.54" r="5" class="lsp"/><text x="241" y="232.54" class="pv">12.9</text><circle cx="405" cy="252.66" r="5" class="lsp"/><text x="451" y="260.65999999999997" class="pv">9.1</text><circle cx="615" cy="268.2" r="5" class="lsp"/><text x="661" y="276.2" class="pv">7</text><circle cx="825" cy="272.64" r="5" class="lsp"/><text x="871" y="280.64" class="pv">6.4</text><circle cx="1035" cy="266.71999999999997" r="5" class="lsp"/><text x="1081" y="274.71999999999997" class="pv">7.2</text><circle cx="1245" cy="250.44" r="5" class="lsp"/><text x="1291" y="258.44" class="pv">9.4</text><circle cx="1455" cy="220.84" r="5" class="lsp"/><text x="1501" y="228.84" class="pv">13.4</text><polyline class="lt" points="195,142.4 405,115.75999999999999 615,95.04000000000002 825,78.75999999999999 1035,68.4 1245,62.48000000000002 1455,69.88000000000002"/><circle cx="195" cy="142.4" r="5" class="ltp"/><text x="241" y="132.4" class="pv">22</text><circle cx="405" cy="115.75999999999999" r="5" class="ltp"/><text x="451" y="105.75999999999999" class="pv">23.8</text><circle cx="615" cy="95.04000000000002" r="5" class="ltp"/><text x="661" y="85.04000000000002" class="pv">25.2</text><circle cx="825" cy="78.75999999999999" r="5" class="ltp"/><text x="871" y="68.75999999999999" class="pv">26.3</text><circle cx="1035" cy="68.4" r="5" class="ltp"/><text x="1081" y="58.400000000000006" class="pv">27</text><circle cx="1245" cy="62.48000000000002" r="5" class="ltp"/><text x="1291" y="52.48000000000002" class="pv">27.4</text><circle cx="1455" cy="69.88000000000002" r="5" class="ltp"/><text x="1501" y="59.880000000000024" class="pv">26.9</text><line x1="90" x2="1560" y1="320" y2="320" class="base"/><text x="195" y="360" class="ax" text-anchor="middle">9:30</text><text x="405" y="360" class="ax" text-anchor="middle">10:30</text><text x="615" y="360" class="ax" text-anchor="middle">11:30</text><text x="825" y="360" class="ax" text-anchor="middle">12:30</text><text x="1035" y="360" class="ax" text-anchor="middle">13:30</text><text x="1245" y="360" class="ax" text-anchor="middle">14:30</text><text x="1455" y="360" class="ax" text-anchor="middle">15:30</text></svg>
  </div>
  <p class="src">예시 값 — 태양 고도·그림자(10cm 막대)는 9월 중순 북위 36° 기준 계산, 기온은 교과서 그래프 모양을 따른 값</p>
</section>
<section class="slide">
  <i class="vline"></i>
  <div class="geo mid" style="left:1380px;top:620px;width:640px;height:640px"></div>
  <div class="lab tl">관계 정리</div>
  <h2 class="hd">태양 고도가 바뀌면 무엇이 달라질까요?</h2>
  <div class="cmp"><div class="card cc"><span class="icon">I</span><h3>태양 고도가 높을 때</h3><p>그림자 길이는 짧아져요</p><p>기온은 높아져요</p></div><div class="card cc"><span class="icon">II</span><h3>태양 고도가 낮을 때</h3><p>그림자 길이는 길어져요</p><p>기온은 낮아져요</p></div></div>
  <div class="tbl"><div class="tr th"><span>시각</span><span>태양 고도</span><span>그림자 길이</span><span>기온</span></div><div class="tr"><span>오전 9:30</span><span>낮아요</span><span>길어요</span><span>낮아요</span></div><div class="tr"><span>낮 12:30</span><span>가장 높아요</span><span>가장 짧아요</span><span>높아지는 중</span></div><div class="tr"><span>오후 14:30</span><span>낮아지는 중</span><span>길어지는 중</span><span>가장 높아요</span></div></div>
  <div class="lst"><span class="lab">남중</span><div class="arow sm"><span class="an">I</span><p>태양이 정남쪽에 있을 때 '남중했다'고 해요</p></div><div class="arow sm"><span class="an">II</span><p>이때의 태양 고도를 남중 고도라고 해요</p></div></div>
  <blockquote class="qt"><span class="qm">“</span><p>태양 고도가 가장 높은 시각과 기온이 가장 높은 시각에는 차이가 있어요.</p><span class="lab">오늘의 정리</span></blockquote>
  <p class="nr">표 규칙 없음 → 목록 행으로 표현</p>
</section>
<section class="slide">
  <i class="vline"></i>
  <div class="geo big" style="left:50%;top:50%;margin:-480px 0 0 -480px;width:960px;height:960px"></div>
  <div class="lab tl">확인하기</div>
  <h2 class="hd">배운 내용을 확인해 볼까요?</h2>
  <div class="card quiz" data-quiz data-answer="1" data-right="정답! 태양 고도가 가장 높을 때(남중) 그림자가 가장 짧아요" data-wrong="다시 생각해 볼까요? 태양 고도와 그림자 길이의 관계를 떠올려 보세요">
    <h3 class="q">하루 중 그림자 길이가 가장 짧을 때는?</h3>
    <div class="rows"><button class="row" data-opt="0"><span class="an">I</span><span class="ot">오전 9시 30분</span></button><button class="row" data-opt="1"><span class="an">II</span><span class="ot">낮 12시 30분 무렵</span></button><button class="row" data-opt="2"><span class="an">III</span><span class="ot">오후 3시 30분</span></button></div>
    <p class="fb" data-fb></p>
    <div class="btns"><button class="sq" data-act="retry">다시 풀기 ↺</button></div>
  </div>
  <div class="card blk">
    <span class="lab">빈칸을 눌러 확인해요</span>
    <p class="bl"><button class="blank" data-blank aria-pressed="false"><span>태양 고도</span></button>는 점점 높아졌다가 다시 낮아진다</p><p class="bl"><button class="blank" data-blank aria-pressed="false"><span>그림자 길이</span></button>는 점점 짧아졌다가 다시 길어진다</p><p class="bl"><button class="blank" data-blank aria-pressed="false"><span>기온</span></button>은 점점 높아졌다가 다시 낮아진다</p>
    <span class="lab wl">오늘의 낱말</span>
    <p class="words">태양 고도 · 남중 고도 · 그림자 길이 · 기온</p>
  </div>
  <i class="haccent end"></i>
  <p class="nr">빈칸 규칙 없음 → 1px 선 칸으로 표현</p>
</section>
<section class="slide">
  <i class="vline"></i>
  <div class="geo mid" style="left:-180px;bottom:-260px;width:620px;height:620px"></div>
  <div class="lab tl">디자인 안내</div>
  <h2 class="hd">이 디자인 사용 설명서</h2>
  <div class="agenda g6"><div class="arow"><span class="an">I</span><div><h3>한눈에</h3><p>박물관 도록처럼 <b>사암색 종이와 타우프 1px 선</b>만으로 구조를 짜요. 강조색이 없고, 굵게 쓰지 않으며, 그림자도 없습니다.</p></div></div><div class="arow"><span class="an">II</span><div><h3>색</h3><p><span class="sw6"><span><i style="background:#EDE8E0"></i>사암</span><span><i style="background:#E2DBD1"></i>짙은 돌</span><span><i style="background:#B8B0A4"></i>타우프 선</span><span><i style="background:#8A8178"></i>라벨 타우프</span><span><i style="background:#1A1A1A"></i>잉크</span></span></p></div></div><div class="arow"><span class="an">III</span><div><h3>글꼴</h3><p>제목·숫자 Playfair Display 400(굵게 금지) → Cafe24 Oneprettynight<br>본문 Inter → 프리텐다드 Pretendard-Light</p></div></div><div class="arow"><span class="an">IV</span><div><h3>이렇게 쓰면 좋아요</h3><p>자료·작품을 차분히 살펴보는 수업, 개념을 정의하는 장. 한 장에 컴퍼스 원은 한두 개만.</p></div></div></div>
  <div class="lab sl6">대표 장치 — 눌러 보세요</div>
  <div class="card d6 a"><div class="dh"><h3>사각 단추 반전</h3><span class="mic">직접 올려 보세요</span></div><p>마우스를 올리면 잉크색으로 뒤집혀요(0.25초).</p><div class="dr"><button class="sq">다음 단계 →</button><button class="sq">처음부터</button></div></div>
  <div class="card d6 b"><div class="dh"><h3>트레이싱지 겹치기</h3><button class="sq sm" data-demo="#ct-tr" data-mode="toggle" aria-pressed="false">켜기 / 끄기</button></div><p>반투명 흰 카드가 컴퍼스 원 위에 얹혀 뒤가 비쳐 보여요.</p><div class="dr trc"><i class="geo6"></i><div class="tr6" id="ct-tr"><span class="an">II</span> 측정기</div></div></div>
  <div class="card d6 c"><div class="dh"><h3>실선과 점선 계열</h3><button class="sq sm" data-demo="#ct-ln" data-mode="toggle" aria-pressed="false">켜기 / 끄기</button></div><p>주 계열은 잉크 실선, 비교 계열은 타우프 5/5 점선으로 겹쳐요.</p><div class="dr"><svg class="ln6" id="ct-ln" viewBox="0 0 560 70"><path class="g" d="M0 35H560M0 68H560"/><polyline class="m" points="10,60 90,40 170,22 250,14 330,24 410,40 490,62"/><polyline class="s" points="10,50 90,42 170,32 250,26 330,22 410,20 490,24"/></svg></div></div>
  <p class="nr">버튼 규칙 없음 → 사각 화살표 단추 모양으로 표현</p>
</section>
<nav class="dk-nav"><span class="dk-dots"><button class="dk-dot" aria-label="1장"></button><button class="dk-dot" aria-label="2장"></button><button class="dk-dot" aria-label="3장"></button><button class="dk-dot" aria-label="4장"></button><button class="dk-dot" aria-label="5장"></button><button class="dk-dot" aria-label="6장"></button></span><span class="nb"><button class="dk-prev" aria-label="이전">←</button><button class="dk-next" aria-label="다음">→</button></span><span class="dk-count" data-pad></span></nav>
  </main>
</div>

<!-- 슬라이드 넘김·단계 버튼·퀴즈 엔진. 이 줄은 지우거나 바꾸지 마세요 -->
<script src="https://k-slide.web.app/kit/v1/cartesian.js"></script>
</body>
</html>
```

---

## 5. 참고: 공통 CSS와 엔진 사용법 (뼈대가 이미 불러옴 — HTML에 옮겨 쓰지 마세요)

아래는 `https://k-slide.web.app/kit/v1/cartesian.css`의 내용과 엔진(`https://k-slide.web.app/kit/v1/cartesian.js`)의 사용법 주석입니다. 클래스의 모양·크기·배치를 이해하는 데에만 쓰세요. 이 내용을 `<style>`이나 `<script>`에 넣으면 안 됩니다.

```css
/* cartesian — k-slide 공통 CSS v1 (채팅 AI용 받기 .md가 불러옴, 고치지 말 것) */
/* === KOREAN FONTS === */
@font-face{font-family:'kp-9';font-display:swap;src:url("https://maker-ssam.github.io/korean-ofl-fonts/fonts/cafe24-oneprettynight/Cafe24Oneprettynight-v2.0.woff2") format("woff2");font-weight:400}
@font-face{font-family:'kp-14';font-display:swap;src:url("https://maker-ssam.github.io/korean-ofl-fonts/fonts/pretendard/Pretendard-Light.woff2") format("woff2");font-weight:300}
/* === THEME === */
:root{--stage-bg:#EDE8E0;--slide-bg:#EDE8E0;
  --kt:'kp-9';--kb:'kp-14';--ka:'kp-14';
  --wt:400;--wb:300}
*{margin:0;padding:0;box-sizing:border-box}
body{font-synthesis:none;word-break:keep-all;letter-spacing:0}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
button:disabled{cursor:default}
/* === VIEWPORT BASE (frontend-slides, mandatory) === */
/* ===========================================
   FIXED 16:9 STAGE: MANDATORY BASE STYLES
   Include this ENTIRE file in every presentation.
   Slides are authored at 1920×1080 and scaled as a whole.
   =========================================== */

/* 1. Lock the browser viewport */
html,
body {
    width: 100%;
    height: 100%;
    margin: 0;
    overflow: hidden;
    background: var(--stage-bg, #000);
}

/* 2. Full-window deck viewport */
.deck-viewport {
    position: fixed;
    inset: 0;
    overflow: hidden;
    background: var(--stage-bg, #000);
}

/* 3. Fixed 16:9 design canvas.
   JavaScript sets transform: translate(...) scale(...). */
.deck-stage {
    position: absolute;
    left: 0;
    top: 0;
    width: 1920px;
    height: 1080px;
    overflow: hidden;
    transform-origin: 0 0;
    background: var(--slide-bg, #fff);
}

/* 4. Slides stack inside the fixed stage.
   Content must be laid out at 1920×1080, not reflowed per device. */
.slide {
    position: absolute;
    inset: 0;
    width: 1920px;
    height: 1080px;
    overflow: hidden;
    display: block;
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    background: var(--slide-bg, #fff);
}

.slide.active,
.slide.visible {
    visibility: visible;
    opacity: 1;
    pointer-events: auto;
    z-index: 1;
}

/* 5. Keep media inside authored slide bounds */
img,
video,
canvas,
svg {
    max-width: 100%;
    max-height: 100%;
}

/* 6. Presentation chrome stays outside the slide design system */
.deck-controls {
    position: fixed;
    left: 50%;
    bottom: 22px;
    transform: translateX(-50%);
    z-index: 1000;
}

/* 7. Print one fixed-size slide per page */
@media print {
    html,
    body {
        width: 1920px;
        height: auto;
        overflow: visible;
        background: #fff;
    }

    .deck-viewport {
        position: static;
        overflow: visible;
        background: #fff;
    }

    .deck-stage {
        position: static;
        width: auto;
        height: auto;
        transform: none !important;
        background: none;
    }

    .slide {
        position: relative;
        display: block !important;
        visibility: visible !important;
        opacity: 1 !important;
        pointer-events: auto !important;
        width: 1920px;
        height: 1080px;
        break-after: page;
        page-break-after: always;
    }

    .slide:last-child {
        break-after: auto;
        page-break-after: auto;
    }

    .deck-controls {
        display: none !important;
    }
}

/* 8. Reduced motion */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.2s !important;
    }
}

/* 동작 줄이기(Windows '애니메이션 효과' 끔 등): 위 규칙이 길이를 0.01ms로 줄이면 반복 애니메이션이 깜빡이듯 빨라짐 → 반복은 한 번만 */
@media (prefers-reduced-motion: reduce){*,*::before,*::after{animation-iteration-count:1 !important}}
.dk-nav{position:absolute;z-index:50}


/* === 측정기 그림(figure-gauge.js) 기본 === */
.gauge{display:block;width:100%;height:auto;overflow:visible;--g-sw:2.5}
.gauge .g-lb{font-family:var(--g-font,var(--kb));font-size:40px;font-weight:700;fill:var(--g-ink,currentColor)}
.gauge .g-ground{stroke:var(--g-ink,currentColor);stroke-width:var(--g-sw);opacity:.35}
.gauge .g-board{fill:var(--g-board,none);stroke:var(--g-ink,currentColor);stroke-width:var(--g-sw)}
.gauge .g-ruler{fill:var(--g-ruler,none);stroke:var(--g-ink,currentColor);stroke-width:var(--g-sw)}
.gauge .g-tick{stroke:var(--g-ink,currentColor);stroke-width:1.5}
.gauge .g-stick{fill:var(--g-stick,var(--g-ink,currentColor));stroke:var(--g-ink,currentColor);stroke-width:var(--g-sw)}
.gauge .g-mark,.gauge .g-lead,.gauge .g-dim,.gauge .g-angle{fill:none;stroke:var(--g-ink,currentColor);stroke-width:var(--g-sw)}
.gauge .g-angle{stroke-width:4}
.gauge .g-shadow{fill:var(--g-shadow,var(--g-ink,currentColor));opacity:.6}
.gauge .g-string{stroke:var(--g-acc,var(--g-ink,currentColor));stroke-width:4}
.gauge .g-prot{fill:var(--g-prot,none);stroke:var(--g-ink,currentColor);stroke-width:var(--g-sw)}
.gauge .g-prot2{fill:none;stroke:var(--g-ink,currentColor);stroke-width:1.5}
.gauge .g-hole{fill:var(--g-ink,currentColor)}
.gauge .g-ray{stroke:var(--g-acc,var(--g-ink,currentColor));stroke-width:7}
.gauge .g-rayh{fill:var(--g-acc,var(--g-ink,currentColor))}
/* 만드는 중(1~3단계): 아직 안 만든 부품과 측정 표시는 흐리게 / 0·4단계는 모두 또렷 */
.slide[data-step="1"] .gauge .g-part:not(.on),.slide[data-step="2"] .gauge .g-part:not(.on),.slide[data-step="3"] .gauge .g-part:not(.on),
.slide[data-step="1"] .gauge .g-meas,.slide[data-step="2"] .gauge .g-meas,.slide[data-step="3"] .gauge .g-meas{opacity:var(--g-dim,.2)}

/* === TEMPLATE STYLES === */

/* --- 토큰(1920 무대: 8vw=154px, 글자는 교실 화면용 최소 28px) --- */
:root{--bg:#EDE8E0;--bg2:#E2DBD1;--ink:#1A1A1A;--t2:#5A5A5A;--acc:#8A8178;--line:#B8B0A4;--white:rgba(255,255,255,.45);--px:200px}
.slide{background:var(--bg);color:var(--ink);font-family:'Inter',var(--kb),sans-serif}
.slide>*{position:absolute}
.lab{font-weight:500;font-size:26px;letter-spacing:.12em;color:var(--acc)}
.lab.tl{left:var(--px);top:80px}.lab.tr{right:150px;top:80px}.lab.bl{left:var(--px);bottom:90px}.lab.br{right:150px;bottom:90px}
.vline{left:154px;top:0;bottom:0;width:1px;background:var(--line);opacity:.3}
.card{background:var(--white);border:1px solid var(--line)}
h3{font-family:'Playfair Display',var(--kt),serif;font-weight:var(--wt);letter-spacing:0}
.hd{left:var(--px);right:150px;top:126px;font-family:'Playfair Display',var(--kt),serif;font-weight:var(--wt);font-size:72px;line-height:1.2;letter-spacing:0}
.icon{display:grid;place-items:center;width:64px;height:64px;border:1px solid var(--line);border-radius:50%;font:400 26px 'Playfair Display',serif;color:var(--acc)}
.an{font:400 34px 'Playfair Display',serif;color:var(--acc)}
.nr{left:var(--px);bottom:30px;font-size:18px;color:var(--acc)}
.sq{border:1px solid var(--line);padding:14px 28px;font-weight:500;font-size:28px;transition:background .25s,color .25s}
.sq:hover:not(:disabled){background:var(--ink);color:var(--bg);border-color:var(--ink)}
.sq:disabled{opacity:.35}
.btns{display:flex;gap:20px}

/* --- 컴퍼스 원: 바깥 실선 + 안쪽(75%) 점선 --- */
.geo{border:1.5px solid var(--line);border-radius:50%;opacity:.5;pointer-events:none}
.geo::before{content:'';position:absolute;inset:12.5%;border:1.5px dashed var(--line);border-radius:50%;opacity:.8}

/* --- 1. 표지: 단원(h3 세리프 + 이탤릭 영문) + 라벨 + 학습 목표(display) + 원 + 세로 보조선 + 하나뿐인 검정 강조선 --- */
.unit{left:var(--px);top:220px;display:flex;align-items:baseline;gap:30px;font-family:'Playfair Display',var(--kt),serif;font-weight:var(--wt);font-size:72px;line-height:1.2;white-space:nowrap}
.unit span{font:italic 400 48px 'Playfair Display',serif;color:var(--acc)}
.lab.gl{left:var(--px);top:400px}
.t1{left:var(--px);top:450px;font-family:'Playfair Display',var(--kt),serif;font-weight:var(--wt);font-size:124px;line-height:1.22;letter-spacing:0;white-space:nowrap}
.t1 .gk{font-style:normal}
.haccent{left:var(--px);bottom:162px;width:384px;height:1px;background:var(--ink)}

/* --- 2. 흐름: 트레이싱지 카드 속 측정기 그림 + 메모 | 정의 + 목록 행 4단계(로마 숫자, 켜지면 잉크) + 사각 단추 --- */
.fig{left:var(--px);top:270px;width:840px;padding:18px 32px 12px;--g-ink:var(--ink);--g-acc:var(--ink);--g-stick:var(--bg2);--g-board:var(--bg2);--g-ruler:var(--bg);--g-prot:rgba(255,255,255,.5);--g-shadow:var(--acc);--g-font:'Inter',var(--kb),sans-serif;--g-sw:1.5}
.mic{font-weight:500;font-size:22px;letter-spacing:.12em;color:var(--acc)}
.fnote{left:var(--px);top:900px;width:840px;font-family:'Playfair Display',var(--kt),serif;font-size:34px;line-height:1.4}
.side{left:1110px;right:150px;top:270px;bottom:110px;display:flex;flex-direction:column}
.def{font-size:28px;line-height:1.6;color:var(--t2)}
.agenda{margin-top:16px;border-top:1px solid var(--line)}
.arow{display:grid;grid-template-columns:76px 1fr;gap:12px;align-items:baseline;padding:14px 0;border-bottom:1px solid var(--line)}
.arow h3{font-size:38px;line-height:1.2}
.arow p{margin-top:4px;font-size:28px;line-height:1.55;color:var(--t2)}
.slide[data-step]:not([data-step="0"]) .agenda .arow:not(.on) h3{color:var(--line)}
.slide[data-step]:not([data-step="0"]) .agenda .arow:not(.on) p{color:var(--line)}
.side .btns{margin-top:auto}
.cap{margin-top:16px;min-height:40px;font-size:28px;line-height:1.5;color:var(--t2)}

/* --- 3. 숫자와 그래프: 통계 묶음(1px 윗선 · Playfair 숫자 · 타우프 라벨) + 차트(잉크 막대·실선 / 타우프 점선) --- */
.stats{left:var(--px);right:150px;top:270px;display:grid;grid-template-columns:repeat(4,1fr);gap:56px;border-top:1px solid var(--line);padding-top:24px}
.st{display:flex;flex-direction:column;gap:8px}
.sf{font:400 76px/1 'Playfair Display',var(--kt),serif}
.st p{font-size:28px;line-height:1.5;color:var(--t2)}
.chartw{left:var(--px);right:150px;top:540px;bottom:120px;display:flex;flex-direction:column;gap:8px}
.lg{display:flex;align-items:center;gap:34px;font-size:26px;color:var(--t2)}
.lg .lab{margin-right:auto;font-size:22px}
.k{display:inline-block;width:34px;height:14px;margin-right:10px;vertical-align:middle}
.k.bn{border:1px solid var(--ink);background:rgba(26,26,26,.05)}.k.ls{height:0;border-top:2px solid var(--ink)}.k.lt{height:0;border-top:2px dashed var(--line)}
.cv{flex:1;min-height:0;width:100%}
.cv .gl{stroke:var(--bg2);stroke-width:2}
.cv .base{stroke:var(--line);stroke-width:1}
.cv .ax{font:500 22px 'Inter',sans-serif;fill:var(--acc)}
.cv .bn{fill:rgba(26,26,26,.05);stroke:var(--ink);stroke-width:1}
.cv .bv{font:400 26px 'Playfair Display',serif;fill:var(--ink)}
.cv .ls{fill:none;stroke:var(--ink);stroke-width:2}.cv .lsp{fill:var(--ink)}
.cv .lt{fill:none;stroke:var(--acc);stroke-width:2;stroke-dasharray:5 5}.cv .ltp{fill:var(--bg);stroke:var(--acc);stroke-width:2}
.cv .pv{font:500 22px 'Inter',sans-serif;fill:var(--t2)}
.src{left:var(--px);right:300px;bottom:44px;font-size:20px;color:var(--acc)}

/* --- 4. 비교와 표: 트레이싱지 카드 둘(로마 숫자 원) + 목록 행(남중) / 목록 행 표 + 따옴표 인용 --- */
.cmp{left:var(--px);width:1000px;top:270px;display:grid;grid-template-columns:1fr 1fr;gap:40px}
.cc{padding:30px 34px}
.cc h3{margin:18px 0 8px;font-size:38px;line-height:1.25}
.cc p{font-size:28px;line-height:1.6;color:var(--t2)}
.lst{left:1270px;right:150px;top:270px;display:flex;flex-direction:column}
.lst .lab{padding-bottom:10px;border-bottom:1px solid var(--line)}
.arow.sm{grid-template-columns:56px 1fr}
.arow.sm p{margin:0;font-size:28px;line-height:1.5;color:var(--t2)}
.tbl{left:var(--px);width:1000px;top:640px;border-top:1px solid var(--line)}
.tr{display:grid;grid-template-columns:1.2fr 1fr 1fr 1fr;gap:16px;padding:12px 0;border-bottom:1px solid var(--line);font-size:28px;line-height:1.4;color:var(--t2)}
.tr span:first-child{font-family:'Playfair Display',var(--kt),serif;color:var(--ink)}
.tr.th{font-weight:500;font-size:22px;letter-spacing:.12em;color:var(--acc)}
.tr.th span:first-child{font-family:'Inter',var(--kb),sans-serif;color:var(--acc)}
.qt{left:1270px;right:150px;top:640px}
.qm{display:block;font:400 110px/.6 'Playfair Display',serif;color:var(--acc);opacity:.5}
.qt p{margin-top:16px;font-family:'Playfair Display',var(--kt),serif;font-weight:var(--wt);font-size:38px;line-height:1.45}
.qt .lab{display:block;margin-top:16px;font-size:22px}

/* --- 5. 확인하기: 트레이싱지 퀴즈 카드(목록 행 보기 · 정답 = 잉크 반전) | 빈칸 카드(1px 선 칸) + 낱말 + 가운데 큰 원 + 검정 강조선 --- */
.quiz{left:var(--px);width:900px;top:270px;bottom:120px;padding:40px 46px;display:flex;flex-direction:column}
.q{font-size:50px;line-height:1.3}
.rows{margin-top:24px;border-top:1px solid var(--line)}
.row{width:100%;display:grid;grid-template-columns:76px 1fr;align-items:center;text-align:left;padding:16px 12px;border-bottom:1px solid var(--line)}
.row .ot{font-size:34px}
.row.right{background:var(--ink);color:var(--bg)}
.row.right .an{color:var(--bg)}
.row.wrong .ot{color:var(--acc)}
.row:disabled:not(.right){opacity:.5}
.fb{margin-top:20px;min-height:90px;font-size:30px;line-height:1.6;color:var(--t2)}
.quiz .btns{margin-top:auto}
.blk{left:1160px;right:150px;top:270px;bottom:120px;padding:36px 40px;display:flex;flex-direction:column;gap:22px}
.bl{font-size:30px;line-height:1.6;color:var(--t2)}
.blank{position:relative;min-width:180px;margin-right:10px;padding:2px 14px;border:1px solid var(--line);font-family:'Playfair Display',var(--kt),serif;font-size:30px;color:var(--ink);text-align:center}
.blank span{visibility:hidden}
.blank::after{content:'?';position:absolute;left:0;right:0;color:var(--acc)}
.blank.open{background:var(--bg2)}
.blank.open span{visibility:visible}
.blank.open::after{content:none}
.wl{margin-top:auto}
.words{font-family:'Playfair Display',var(--kt),serif;font-size:40px;line-height:1.35}
.haccent.end{left:auto;right:150px;bottom:80px}

/* --- 내비: 오른쪽 점 + 왼쪽 아래 사각 화살표 + 오른쪽 아래 번호 --- */
.dk-nav{inset:0;pointer-events:none}
.dk-dots{position:absolute;right:50px;top:50%;transform:translateY(-50%);display:flex;flex-direction:column;gap:18px;pointer-events:auto}
.dk-dot{width:12px;height:12px;border-radius:50%;background:var(--line)}
.dk-dot.on{background:var(--ink);transform:scale(1.3)}
.nb{position:absolute;left:30px;bottom:24px;display:flex;gap:10px;pointer-events:auto}
.nb button{width:56px;height:56px;border:1px solid var(--line);font-size:24px;transition:background .25s,color .25s}
.nb button:hover:not(:disabled){background:var(--ink);color:var(--bg)}
.nb button:disabled{opacity:.3}
.dk-count{position:absolute;right:50px;bottom:40px;font-weight:500;font-size:24px;letter-spacing:.12em;color:var(--acc)}
/* --- 6. 디자인 안내: 목록 행 넷 | 트레이싱지 카드 시연 3개 --- */
.g6{left:var(--px);width:820px;top:270px}
.g6 .arow{grid-template-columns:70px 1fr;padding:18px 0}
.g6 h3{font-size:36px}
.g6 p{margin-top:4px;font-size:25px;line-height:1.55;color:var(--t2)}
.g6 b{font-weight:600;color:var(--ink)}
.sw6{display:flex;flex-wrap:wrap;gap:6px 20px}
.sw6 i{display:inline-block;width:26px;height:26px;margin-right:8px;vertical-align:-6px;border:1px solid var(--line)}
.lab.sl6{left:1110px;top:270px}
.d6{left:1110px;right:150px;height:206px;padding:18px 28px}
.d6.a{top:322px}.d6.b{top:548px}.d6.c{top:774px}
.d6 .dh{display:flex;justify-content:space-between;align-items:center;gap:16px}
.d6 h3{font-size:32px}
.d6 p{margin-top:4px;font-size:21px;line-height:1.4;color:var(--t2)}
.sq.sm{font-size:20px;padding:6px 16px}
.sq.sm[aria-pressed="true"]{background:var(--ink);color:var(--bg);border-color:var(--ink)}
.dr{margin-top:12px;height:76px;display:flex;align-items:center;gap:18px}
.dr .sq{font-size:22px;padding:10px 20px}
.trc{position:relative}
.geo6{position:absolute;left:20px;top:-14px;width:110px;height:110px;border:1.5px solid var(--line);border-radius:50%}
.geo6::before{content:'';position:absolute;inset:12.5%;border:1.5px dashed var(--line);border-radius:50%}
.tr6{position:relative;margin-left:70px;padding:12px 26px;font:400 28px 'Playfair Display',var(--kt),serif;border:1px solid transparent}
.tr6.play{background:var(--white);border-color:var(--line)}
.ln6{width:100%;height:70px}
.ln6 .g{stroke:var(--bg2);stroke-width:1.5;fill:none}
.ln6 .m{fill:none;stroke:var(--ink);stroke-width:2}
.ln6 .s{fill:none;stroke:var(--acc);stroke-width:2;stroke-dasharray:5 5;opacity:0}
.ln6.play .s{opacity:1}

/* === DECK ENGINE (slide-refs 공용, 덱 HTML에 그대로 인라인됨) ===
   window.DECK_CFG = { type: 'x' | 'y' | 'fade' | 'shift' | 'rise', dur: ms, ease: css, dist: px, wheel: bool }
   window.DECK_FX  = { enter(slide, i), step(slide, k), answer(quiz, ok, btn) }  // 템플릿별 효과 훅(선택)
   - 넘김: → ↓ Space PageDown Enter = 다음(단계가 남았으면 단계 먼저), ← ↑ PageUp = 이전, Home/End
   - 내비: .dk-dot(점) .dk-count(번호, data-pad면 01 형식) .dk-prev .dk-next
   - 단계: <section data-steps="4"> 안의 [data-s="k"] 요소가 k단계부터 .on, 현재 단계는 .now
           [data-caps='["...",...]'] 요소의 글이 단계마다 바뀜, 버튼 [data-act="step"] [data-act="reset"]
   - 퀴즈: [data-quiz data-answer data-right data-wrong] 안의 버튼 [data-opt="i"], 결과 글 [data-fb], 다시 풀기 [data-act="retry"]
   - 빈칸: [data-blank] 를 누르면 .open (답 보이기/숨기기)
   - 시연(6장 디자인 안내): 버튼 [data-demo="선택자"] 를 누르면 같은 장 안의 그 요소에 .play
       data-mode="toggle" 이면 .play 켜기/끄기(aria-pressed), 아니면 .play를 뺐다 다시 붙여 애니메이션을 처음부터 다시 재생 */
```

(끝. 사용자의 수업 내용을 받아 위 지시대로 HTML을 만드세요.)
