sqzass.git

sqzass

~ A static site generator written in Rust
git clone https://github.com/debuman/sqzass.git
commit fa79d021fec6ababd54fd1eb4e820fdca1857748
parent e9079c27d6bd627aa70360db81ff3822c89888f1
Author: sqzer <110329244+sqzer-x@users.noreply.github.com>
Date: Thu, 30 Jul 2026 22:48:11 +0900

랜딩을 심해 발광으로 다시 그린다

첫 판은 밝은 기록지 콘셉트였는데 사용자가 상용 수준이 아니라고
반려했다. hwaro·gori를 실렌더로 뜯어 공통 언어를 확인했다: 칠흑
캔버스, 초대형 헤드라인, 그라디언트 한 포인트, 동양화풍 아트워크,
설치 칩, 앰비언트 장식. 우리 축은 로고(오징어)에서: 먹물·심해·
생물발광. 손으로 쓴 인라인 SVG 먹물결 원판(외부 이미지 없음),
발광 시안 그라디언트, box-shadow 점묘 플랑크톤, JetBrains Mono
셀프호스트(woff2 21KB×2), 히어로 설치 칩에 복사 버튼(t(copy)/
t(copied) 재사용), 퀵스타트는 실행 원문 그대로의 터미널 세션.

검증에서 잡은 함정: 헤드리스가 스크립트 시점엔 780×493으로
레이아웃한 뒤 리사이즈해서, inView 리빌이 '화면 밖'으로 판정돼
캡처에만 안 나온다 — 실브라우저 동작은 정상. 레이아웃 검증은
--force-prefers-reduced-motion(연출 전량 스킵 경로)으로 찍는 걸로
레시피를 바꿨다. 좁은 window-size도 무시된다(500px부터 유효).

Diffstat:
Mdocs/content/_index.ko.md | 1+
Mdocs/content/_index.md | 1+
Mdocs/static/css/landing.css | 452++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Adocs/static/fonts/jetbrains-mono-400.woff2 | 0binary
Adocs/static/fonts/jetbrains-mono-700.woff2 | 0binary
Mdocs/static/js/landing.js | 42+++++++++++++++++++++++++++++++++++-------
Mdocs/templates/landing.html | 175+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
7 files changed, 462 insertion(+), 209 deletion(-)

diff --git a/docs/content/_index.ko.md b/docs/content/_index.ko.md
@@ -10,6 +10,7 @@ hero_title_a = "천 페이지,"
 hero_title_b = "25밀리초."
 hero_sub = "sqzass는 빠르고, 그걸 증명합니다: 생성기 다섯을 같은 머신, 같은 코퍼스로 재고 방법을 공개했습니다. 출력물은 어느 호스트에서든 그대로 동작합니다."
 cta_start = "시작하기"
+cta_github = "GitHub에서 보기"
 
 bench_title = "주장이 아니라 측정입니다"
 bench_note = "각 줄은 우리가 잰 네 생성기 중 가장 빠른 Hugo와 비교합니다 — 같은 머신, 콜드 빌드, 3회 중앙값. 막대는 줄 안에서 실척이고, sqzass 시간에는 검색 색인·sitemap·llms.txt 생성이 포함돼 있습니다."
diff --git a/docs/content/_index.md b/docs/content/_index.md
@@ -10,6 +10,7 @@ hero_title_a = "One thousand pages."
 hero_title_b = "Twenty-five milliseconds."
 hero_sub = "sqzass builds fast and proves it: five generators, one machine, one corpus, method published. The output is correct on any host."
 cta_start = "Get started"
+cta_github = "View on GitHub"
 
 bench_title = "Measured, not claimed"
 bench_note = "Each row compares sqzass with Hugo, the fastest of the four generators we measured — same machine, cold builds, median of three. Bars are to scale within each row, and the sqzass times include building the search index, sitemap and llms.txt."
diff --git a/docs/static/css/landing.css b/docs/static/css/landing.css
@@ -1,24 +1,40 @@
-/* 랜딩 전용 스타일. docs(main.css)와 의도적으로 독립 — 다크+주황의 문서와 달리
-   랜딩은 "측정 기록지"다: 밝은 시트, 쪽빛 잉크, 눈금자, 실척 막대.
-   단일 테마로 커밋한다([data-theme] 없음) — 하이라이트 CSS가 없어 결합할 이유가
-   없고, 랜딩은 한 번 보는 포스터지 읽기 표면이 아니다. */
+/* 랜딩 전용 스타일. docs(main.css)와 의도적으로 독립.
+   콘셉트: 심해 발광 — sqzass 로고(오징어)에서 먹물·심해·생물발광으로.
+   칠흑 인디고 캔버스, 시안 발광 악센트, 먹물결 원판 아트, 앰비언트 별점.
+   테마는 다크 하나로 커밋한다([data-theme] 없음). 인라인 style 금지 —
+   장식은 전부 이 시트와 인라인 SVG의 표현 속성이 진다. */
+
+@font-face {
+  font-family: "JetBrains Mono";
+  src: url("/fonts/jetbrains-mono-400.woff2") format("woff2");
+  font-weight: 400;
+  font-style: normal;
+  font-display: swap;
+}
+@font-face {
+  font-family: "JetBrains Mono";
+  src: url("/fonts/jetbrains-mono-700.woff2") format("woff2");
+  font-weight: 700;
+  font-style: normal;
+  font-display: swap;
+}
 
 :root {
-  --sheet: #f1f3f5;      /* 종이 */
-  --card: #fafbfc;       /* 들린 면 */
-  --ink: #0f1c2e;        /* 본문 잉크 */
-  --ink-2: #4a5a6d;      /* 보조 잉크 */
-  --rule: #c8d1da;       /* 괘선·눈금 */
-  --jjok: #1b45d7;       /* 쪽빛 — 텍스트 악센트 (4.5:1 이상) */
-  --jjok-bright: #2e63ff;/* 쪽빛 — 그래픽 악센트 (대형 요소용) */
-  --bar-other: #a7b3c0;  /* 비교군 막대 */
-  --code-bg: #0f1c2e;
-  --code-ink: #dfe7ee;
+  --abyss: #05070d;          /* 심연 */
+  --abyss-2: #090d18;        /* 한 층 위 */
+  --panel: rgba(148, 184, 255, 0.04);
+  --line: rgba(148, 184, 255, 0.12);
+  --line-2: rgba(148, 184, 255, 0.22);
+  --text: #e9eef7;
+  --muted: #93a0b6;
+  --glow: #59d8ff;           /* 발광 시안 */
+  --glow-deep: #2e63ff;      /* 심층 블루 */
+  --bar-other: #38445c;
   --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
           "Noto Sans KR", "Apple SD Gothic Neo", sans-serif;
-  --mono: ui-monospace, "SF Mono", "Cascadia Code", Consolas, monospace;
-  --wrap: 68rem;
-  color-scheme: light;
+  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Consolas, monospace;
+  --wrap: 72rem;
+  color-scheme: dark;
 }
 
 * { box-sizing: border-box; }
@@ -26,39 +42,52 @@
 html { scroll-behavior: smooth; }
 
 body {
+  position: relative;
   margin: 0;
-  background: var(--sheet);
-  color: var(--ink);
+  background: var(--abyss);
+  color: var(--text);
   font-family: var(--sans);
   font-size: 1.0625rem;
   line-height: 1.7;
   -webkit-text-size-adjust: 100%;
+  overflow-x: hidden;
 }
 
-/* ── 눈금자 레일: 페이지의 서명. 왼쪽 가장자리를 측정 도구로 만든다 ── */
-@media (min-width: 64rem) {
-  body {
-    padding-left: 2.75rem;
-  }
-  body::before {
-    content: "";
-    position: fixed;
-    inset: 0 auto 0 0;
-    width: 2.75rem;
-    border-right: 1px solid var(--rule);
-    background-image:
-      repeating-linear-gradient(to bottom, var(--rule) 0 1px, transparent 1px 8px),
-      repeating-linear-gradient(to bottom, var(--ink-2) 0 1px, transparent 1px 64px);
-    background-size: 0.7rem 100%, 1.15rem 100%;
-    background-position: right center;
-    background-repeat: no-repeat;
-    pointer-events: none;
-  }
+/* 앰비언트: 발광 플랑크톤. box-shadow 점묘 두 겹 + 히어로 뒤 방사 광. */
+body::before {
+  content: "";
+  position: absolute;
+  inset: 0;
+  height: 220vh;
+  pointer-events: none;
+  background:
+    radial-gradient(52rem 36rem at 78% 22rem, rgba(46, 99, 255, 0.13), transparent 65%),
+    radial-gradient(40rem 30rem at 18% 8rem, rgba(89, 216, 255, 0.06), transparent 60%);
+}
+.specks, .specks::after {
+  content: "";
+  position: absolute;
+  inset: 0;
+  height: 220vh;
+  pointer-events: none;
+}
+.specks {
+  background-image:
+    radial-gradient(1.5px 1.5px at 12% 18%, rgba(143, 229, 255, 0.8), transparent 100%),
+    radial-gradient(1px 1px at 34% 9%, rgba(143, 229, 255, 0.5), transparent 100%),
+    radial-gradient(1.5px 1.5px at 58% 26%, rgba(201, 242, 255, 0.7), transparent 100%),
+    radial-gradient(1px 1px at 71% 7%, rgba(143, 229, 255, 0.55), transparent 100%),
+    radial-gradient(1px 1px at 88% 33%, rgba(143, 229, 255, 0.45), transparent 100%),
+    radial-gradient(1.5px 1.5px at 44% 41%, rgba(143, 229, 255, 0.35), transparent 100%),
+    radial-gradient(1px 1px at 8% 55%, rgba(143, 229, 255, 0.3), transparent 100%),
+    radial-gradient(1px 1px at 93% 62%, rgba(143, 229, 255, 0.35), transparent 100%),
+    radial-gradient(1.5px 1.5px at 26% 74%, rgba(143, 229, 255, 0.25), transparent 100%),
+    radial-gradient(1px 1px at 66% 87%, rgba(143, 229, 255, 0.3), transparent 100%);
 }
 
-a { color: var(--jjok); text-decoration: none; }
+a { color: var(--glow); text-decoration: none; }
 a:hover { text-decoration: underline; text-underline-offset: 3px; }
-:focus-visible { outline: 2px solid var(--jjok); outline-offset: 2px; border-radius: 2px; }
+:focus-visible { outline: 2px solid var(--glow); outline-offset: 3px; border-radius: 3px; }
 
 img { max-width: 100%; }
 
@@ -66,18 +95,20 @@ img { max-width: 100%; }
   position: absolute;
   left: -999px;
   top: 0;
-  background: var(--ink);
-  color: var(--sheet);
+  background: var(--glow);
+  color: #04121a;
   padding: 0.5rem 1rem;
   z-index: 10;
+  font-weight: 700;
 }
 .skip:focus { left: 0.5rem; top: 0.5rem; }
 
 /* ── 상단 스트립 ── */
 .topbar {
+  position: relative;
   max-width: var(--wrap);
   margin: 0 auto;
-  padding: 1.1rem clamp(1.25rem, 4vw, 2.5rem);
+  padding: 1.15rem clamp(1.25rem, 4vw, 2.5rem);
   display: flex;
   align-items: center;
   justify-content: space-between;
@@ -86,218 +117,331 @@ img { max-width: 100%; }
 .mark {
   display: inline-flex;
   align-items: center;
-  gap: 0.55rem;
-  color: var(--ink);
-  font-weight: 800;
-  font-size: 1.1rem;
+  gap: 0.6rem;
+  color: var(--text);
+  font-weight: 700;
+  font-size: 1.08rem;
+  letter-spacing: 0.01em;
 }
 .mark:hover { text-decoration: none; }
-.mark img { width: 26px; height: 26px; }
+.mark img { width: 27px; height: 27px; filter: invert(1); }
 .topnav {
   display: flex;
   align-items: center;
-  gap: 1.4rem;
-  font-weight: 600;
-  font-size: 0.95rem;
+  gap: 1.35rem;
+  font-size: 0.93rem;
+  font-weight: 500;
+}
+.topnav > a { color: var(--muted); }
+.topnav > a:hover { color: var(--text); text-decoration: none; }
+.langs {
+  display: inline-flex;
+  border: 1px solid var(--line);
+  border-radius: 999px;
+  overflow: hidden;
 }
-.topnav a { color: var(--ink-2); }
-.topnav a:hover { color: var(--jjok); text-decoration: none; }
+.lang-pill {
+  padding: 0.22rem 0.7rem;
+  font-family: var(--mono);
+  font-size: 0.72rem;
+  font-weight: 700;
+  color: var(--muted);
+}
+.lang-pill:hover { color: var(--text); background: var(--panel); text-decoration: none; }
+.gh { color: var(--muted); display: inline-flex; }
+.gh:hover { color: var(--text); }
 
-main { display: block; }
+main { position: relative; display: block; }
 
 section, .foot { padding-inline: clamp(1.25rem, 4vw, 2.5rem); }
 .inner { max-width: var(--wrap); margin: 0 auto; }
 
 /* ── 히어로 ── */
-.hero { padding-block: clamp(4rem, 10vw, 7.5rem) clamp(3rem, 7vw, 5rem); }
-.kicker {
-  margin: 0 0 1.1rem;
-  color: var(--jjok);
-  font-weight: 700;
-  font-size: 0.95rem;
-  display: flex;
+.hero { padding-block: clamp(4rem, 9vw, 7rem) clamp(3.5rem, 7vw, 5.5rem); }
+.hero-grid {
+  display: grid;
+  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
   align-items: center;
-  gap: 0.6rem;
+  gap: clamp(2rem, 5vw, 4.5rem);
 }
-.kicker::before {
-  content: "";
-  width: 1.6rem;
-  height: 2px;
-  background: var(--jjok);
-  flex: none;
+.kicker {
+  margin: 0 0 1.3rem;
+  display: inline-flex;
+  align-items: center;
+  gap: 0.5rem;
+  padding: 0.32rem 0.85rem;
+  border: 1px solid var(--line);
+  border-radius: 999px;
+  background: var(--panel);
+  color: var(--glow);
+  font-family: var(--mono);
+  font-size: 0.78rem;
+  font-weight: 700;
 }
 .display {
   margin: 0;
-  font-size: clamp(2.5rem, 6.5vw, 4.5rem);
-  line-height: 1.06;
+  font-size: clamp(2.7rem, 5.6vw, 4.6rem);
+  line-height: 1.05;
   font-weight: 800;
-  letter-spacing: -0.02em;
-  max-width: 18ch;
+  letter-spacing: -0.025em;
   text-wrap: balance;
 }
 .display em {
   font-style: normal;
-  color: var(--jjok);
+  background: linear-gradient(92deg, var(--glow) 10%, #7aa2ff 55%, var(--glow-deep) 100%);
+  -webkit-background-clip: text;
+  background-clip: text;
+  color: transparent;
 }
 .sub {
-  margin: 1.6rem 0 0;
-  max-width: 46ch;
-  font-size: 1.15rem;
-  color: var(--ink-2);
+  margin: 1.5rem 0 0;
+  max-width: 44ch;
+  font-size: 1.13rem;
+  line-height: 1.75;
+  color: var(--muted);
   text-wrap: pretty;
 }
-.cta { margin: 2.2rem 0 0; display: flex; gap: 0.8rem; flex-wrap: wrap; }
+.cta { margin: 2.1rem 0 0; display: flex; gap: 0.75rem; flex-wrap: wrap; }
 .btn {
   display: inline-flex;
   align-items: center;
   min-height: 2.9rem;
-  padding: 0 1.4rem;
-  border: 1px solid var(--ink);
-  border-radius: 2px;
+  padding: 0 1.45rem;
+  border-radius: 999px;
   font-weight: 700;
-  font-size: 1rem;
-  color: var(--ink);
-  transition: transform 0.15s ease, background 0.15s ease, color 0.15s ease;
+  font-size: 0.98rem;
+  transition: transform 0.16s ease, box-shadow 0.16s ease, background 0.16s ease,
+              border-color 0.16s ease;
   cursor: pointer;
 }
 .btn:hover { text-decoration: none; transform: translateY(-1px); }
-.btn-primary { background: var(--ink); color: var(--sheet); }
-.btn-primary:hover { background: var(--jjok); border-color: var(--jjok); }
+.btn-primary {
+  background: linear-gradient(120deg, #6fe0ff, #3d7bff);
+  color: #041220;
+  box-shadow: 0 0 24px rgba(89, 216, 255, 0.35), 0 1px 2px rgba(0, 0, 0, 0.5);
+}
+.btn-primary:hover { box-shadow: 0 0 34px rgba(89, 216, 255, 0.5), 0 2px 6px rgba(0, 0, 0, 0.5); }
+.btn-ghost {
+  color: var(--text);
+  border: 1px solid var(--line-2);
+  background: var(--panel);
+}
+.btn-ghost:hover { border-color: var(--glow); }
+
+.install {
+  margin: 1.9rem 0 0;
+  display: inline-flex;
+  align-items: center;
+  gap: 0.4rem;
+  max-width: 100%;
+  border: 1px solid var(--line);
+  border-radius: 10px;
+  background: rgba(4, 8, 16, 0.8);
+  padding: 0.62rem 0.5rem 0.62rem 0.95rem;
+}
+.install code {
+  font-family: var(--mono);
+  font-size: 0.83rem;
+  color: #bfe9ff;
+  white-space: nowrap;
+  overflow-x: auto;
+  scrollbar-width: none;
+}
+.inst-copy {
+  flex: none;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  width: 2rem;
+  height: 2rem;
+  border: 0;
+  border-radius: 7px;
+  background: transparent;
+  color: var(--muted);
+  cursor: pointer;
+}
+.inst-copy:hover { color: var(--glow); background: var(--panel); }
+.inst-copy .i-check { display: none; }
+.inst-copy.is-done .i-copy { display: none; }
+.inst-copy.is-done .i-check { display: block; color: var(--glow); }
+
+.hero-art { display: flex; justify-content: center; min-width: 0; }
+.art {
+  width: min(100%, 30rem);
+  height: auto;
+  filter: drop-shadow(0 0 46px rgba(46, 99, 255, 0.28));
+}
 
 /* ── 포지셔닝 프로즈 ── */
-.intro { padding-block: 0 clamp(3rem, 7vw, 5rem); }
+.intro { padding-block: 0 clamp(3rem, 6vw, 4.5rem); }
 .intro p {
-  max-width: 62ch;
+  max-width: 64ch;
   margin: 0 0 1.1rem;
-  color: var(--ink-2);
-  font-size: 1.0625rem;
+  color: var(--muted);
+  font-size: 1.05rem;
 }
 
 /* ── 섹션 공통 ── */
-.band { border-top: 1px solid var(--rule); padding-block: clamp(3.5rem, 8vw, 6rem); }
+.band { border-top: 1px solid var(--line); padding-block: clamp(4rem, 8vw, 6.5rem); }
 .band h2 {
-  margin: 0 0 0.8rem;
-  font-size: clamp(1.6rem, 3.2vw, 2.1rem);
-  line-height: 1.2;
+  margin: 0 0 0.9rem;
+  font-size: clamp(1.7rem, 3.4vw, 2.3rem);
+  line-height: 1.15;
   font-weight: 800;
-  letter-spacing: -0.01em;
+  letter-spacing: -0.02em;
 }
+.band-note { max-width: 62ch; margin: 0 0 2.2rem; color: var(--muted); font-size: 0.97rem; }
+.band-more { margin: 2.2rem 0 0; font-weight: 600; }
 
-/* ── 벤치마크: 실척 막대 ── */
-.bench-note { max-width: 62ch; margin: 0 0 2.4rem; color: var(--ink-2); font-size: 0.98rem; }
-.row { margin: 0 0 2rem; }
-.row h3 { margin: 0 0 0.6rem; font-size: 1.02rem; font-weight: 700; }
+/* ── 벤치마크 ── */
+.bench-card {
+  border: 1px solid var(--line);
+  border-radius: 14px;
+  background: linear-gradient(180deg, rgba(20, 34, 64, 0.35), rgba(9, 13, 24, 0.6));
+  padding: clamp(1.4rem, 3vw, 2.4rem);
+}
+.row { margin: 0 0 1.9rem; }
+.row h3 { margin: 0 0 0.55rem; font-size: 1rem; font-weight: 700; color: var(--text); }
 .meas {
   display: grid;
   grid-template-columns: 5.2rem 1fr 7.5rem;
   align-items: center;
-  gap: 0.8rem;
-  margin: 0.35rem 0;
+  gap: 0.85rem;
+  margin: 0.4rem 0;
 }
-.who { font-size: 0.9rem; font-weight: 600; color: var(--ink-2); }
-.meas.us .who { color: var(--jjok); }
-.track { width: 100%; height: 1.35rem; display: block; }
+.who { font-size: 0.86rem; font-weight: 600; color: var(--muted); }
+.meas.us .who { color: var(--glow); }
+.track { width: 100%; height: 1.15rem; display: block; }
 .fill {
   fill: var(--bar-other);
   transform-box: fill-box;
   transform-origin: left center;
 }
-.meas.us .fill { fill: var(--jjok-bright); }
+.meas.us .fill { fill: var(--glow); }
+.meas.us .track { filter: drop-shadow(0 0 8px rgba(89, 216, 255, 0.55)); }
 .val {
   font-family: var(--mono);
   font-variant-numeric: tabular-nums;
-  font-size: 0.98rem;
+  font-size: 0.95rem;
   font-weight: 700;
-  color: var(--ink-2);
-  text-align: left;
+  color: var(--muted);
   white-space: nowrap;
 }
-.meas.us .val { color: var(--jjok); }
+.meas.us .val { color: var(--glow); }
 .zero {
-  margin: 3rem 0 0.4rem;
+  margin: 2.4rem 0 0;
+  padding-top: 1.9rem;
+  border-top: 1px solid var(--line);
   display: flex;
   align-items: baseline;
-  gap: 1rem;
+  gap: 1.1rem;
   flex-wrap: wrap;
 }
 .zero-num {
   font-family: var(--mono);
   font-variant-numeric: tabular-nums;
-  font-size: clamp(3.4rem, 8vw, 5.5rem);
+  font-size: clamp(3.2rem, 7vw, 5rem);
   font-weight: 700;
   line-height: 1;
-  color: var(--jjok);
+  background: linear-gradient(180deg, var(--glow), var(--glow-deep));
+  -webkit-background-clip: text;
+  background-clip: text;
+  color: transparent;
 }
-.zero-label { max-width: 34ch; color: var(--ink-2); font-size: 0.98rem; line-height: 1.55; }
-.bench-more { margin: 2rem 0 0; font-weight: 600; }
+.zero-label { max-width: 36ch; color: var(--muted); font-size: 0.95rem; line-height: 1.6; }
 
 /* ── 기능 카드 ── */
 .cards {
   list-style: none;
-  margin: 2rem 0 0;
+  margin: 2.2rem 0 0;
   padding: 0;
   display: grid;
   grid-template-columns: repeat(3, 1fr);
-  gap: 1.1rem;
+  gap: 1rem;
 }
 .card {
-  background: var(--card);
-  border: 1px solid var(--rule);
-  border-radius: 3px;
-  padding: 1.4rem 1.5rem;
-}
-.card h3 { margin: 0 0 0.5rem; font-size: 1.02rem; font-weight: 700; }
-.card p { margin: 0; font-size: 0.94rem; line-height: 1.65; color: var(--ink-2); }
-.more { margin: 2rem 0 0; font-weight: 600; }
+  position: relative;
+  border: 1px solid var(--line);
+  border-radius: 12px;
+  background: var(--panel);
+  padding: 1.45rem 1.5rem;
+  transition: border-color 0.18s ease, transform 0.18s ease, background 0.18s ease;
+}
+.card:hover {
+  border-color: rgba(89, 216, 255, 0.45);
+  background: rgba(89, 216, 255, 0.05);
+  transform: translateY(-2px);
+}
+.card h3 { margin: 0 0 0.5rem; font-size: 1rem; font-weight: 700; }
+.card p { margin: 0; font-size: 0.92rem; line-height: 1.65; color: var(--muted); }
 
-/* ── 퀵스타트 ── */
-.steps {
-  display: grid;
-  grid-template-columns: 1fr 1fr;
-  gap: 1.1rem;
-  margin: 2rem 0 0;
-}
-/* 그리드 아이템의 min-width:auto가 긴 curl 한 줄에 밀려 열을 뚫는다 —
-   0으로 눌러야 pre의 overflow-x가 일을 한다. */
-.step { min-width: 0; }
-.step h3 { margin: 0 0 0.7rem; font-size: 1.02rem; font-weight: 700; }
-.step pre + pre { margin-top: 0.6rem; }
-.step pre {
+/* ── 터미널 ── */
+.term {
+  border: 1px solid var(--line);
+  border-radius: 12px;
+  background: #070b14;
+  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5), 0 0 40px rgba(46, 99, 255, 0.1);
+  overflow: hidden;
+  max-width: 46rem;
+}
+.term-bar {
+  display: flex;
+  gap: 0.45rem;
+  padding: 0.7rem 1rem;
+  border-bottom: 1px solid var(--line);
+  background: rgba(148, 184, 255, 0.03);
+}
+.term-bar i {
+  width: 0.68rem;
+  height: 0.68rem;
+  border-radius: 50%;
+  background: #2c3750;
+}
+.term pre {
   margin: 0;
-  background: var(--code-bg);
-  color: var(--code-ink);
-  border-radius: 4px;
-  padding: 1.1rem 1.25rem;
+  padding: 1.15rem 1.3rem 1.3rem;
   overflow-x: auto;
   font-family: var(--mono);
-  font-size: 0.88rem;
-  line-height: 1.7;
+  font-size: 0.84rem;
+  line-height: 1.85;
+  color: #d7e4f7;
 }
-.quick-note { margin: 1.6rem 0 0; color: var(--ink-2); font-size: 0.95rem; }
+.t-p { color: var(--glow); font-weight: 700; }
+.t-o { color: #7d8ba3; }
+.quick-note { margin-top: 1.6rem; }
 
 /* ── 푸터 ── */
-.foot { border-top: 1px solid var(--rule); padding-block: 2.6rem 3.2rem; }
+.foot { border-top: 1px solid var(--line); padding-block: 2.6rem 3.4rem; }
 .foot .inner { display: grid; gap: 1.1rem; }
-.foot-nav { display: flex; flex-wrap: wrap; gap: 1.3rem; font-weight: 600; font-size: 0.95rem; }
-.foot p { margin: 0; color: var(--ink-2); font-size: 0.92rem; max-width: 62ch; }
+.foot-nav { display: flex; flex-wrap: wrap; gap: 1.4rem; font-weight: 600; font-size: 0.93rem; }
+.foot-nav a { color: var(--muted); }
+.foot-nav a:hover { color: var(--glow); text-decoration: none; }
+.foot p { margin: 0; color: var(--muted); font-size: 0.9rem; max-width: 64ch; }
 
-/* ── 한국어: 자간·모노·대문자 장치를 한글에 적용하지 않는다 ── */
+/* ── 한국어: 자간·모노·대문자 장치를 한글에 적용하지 않는다.
+      kicker는 모노를 유지해도 되는 게 아니다 — 한글이 폴백 폰트로 가며
+      공백만 모노 폭이 되는 함정(main.css의 결정과 동일). ── */
 html[lang="ko"] .display { letter-spacing: 0; }
 html[lang="ko"] .band h2 { letter-spacing: 0; }
+html[lang="ko"] .kicker { font-family: var(--sans); font-size: 0.83rem; letter-spacing: 0; }
 html[lang="ko"] h1, html[lang="ko"] h2, html[lang="ko"] h3 { word-break: keep-all; }
-html[lang="ko"] .sub, html[lang="ko"] .zero-label { word-break: keep-all; }
+html[lang="ko"] .sub, html[lang="ko"] .zero-label, html[lang="ko"] .band-note { word-break: keep-all; }
 
 /* ── 반응형 ── */
 @media (max-width: 64rem) {
+  .hero-grid { grid-template-columns: 1fr; }
+  .hero-art { order: -1; }
+  .art { width: min(70vw, 21rem); }
   .cards { grid-template-columns: 1fr 1fr; }
+  .topnav > a:first-child { display: none; }
 }
 @media (max-width: 44rem) {
-  .cards, .steps { grid-template-columns: 1fr; }
-  .meas { grid-template-columns: 4.2rem 1fr 6.2rem; gap: 0.6rem; }
-  .topnav { gap: 1rem; }
+  .cards { grid-template-columns: 1fr; }
+  .meas { grid-template-columns: 4rem 1fr 6rem; gap: 0.6rem; }
+  .display { font-size: clamp(2.3rem, 10vw, 2.9rem); }
 }
 
 @media (prefers-reduced-motion: reduce) {
   html { scroll-behavior: auto; }
-  .btn { transition: none; }
+  .btn, .card { transition: none; }
 }
diff --git a/docs/static/fonts/jetbrains-mono-400.woff2 b/docs/static/fonts/jetbrains-mono-400.woff2
Binary files differ.
diff --git a/docs/static/fonts/jetbrains-mono-700.woff2 b/docs/static/fonts/jetbrains-mono-700.woff2
Binary files differ.
diff --git a/docs/static/js/landing.js b/docs/static/js/landing.js
@@ -1,7 +1,25 @@
-/* 랜딩 연출. 전부 점진적 향상이다 — Motion이 없거나 reduced-motion이면
-   아무것도 하지 않고, 페이지는 CSS만으로 완성 상태다. */
+/* 랜딩 연출·복사 버튼. 전부 점진적 향상이다 — Motion이 없거나
+   reduced-motion이면 연출은 생략되고, 페이지는 CSS만으로 완성 상태다. */
 (function () {
   "use strict";
+
+  /* 설치 한 줄 복사. 연출과 무관하므로 reduced-motion과 상관없이 동작한다. */
+  document.querySelectorAll(".inst-copy").forEach(function (btn) {
+    var label = btn.getAttribute("aria-label");
+    btn.addEventListener("click", function () {
+      var text = btn.getAttribute("data-copy-text") || "";
+      if (!navigator.clipboard) return;
+      navigator.clipboard.writeText(text).then(function () {
+        btn.classList.add("is-done");
+        btn.setAttribute("aria-label", btn.getAttribute("data-copied"));
+        setTimeout(function () {
+          btn.classList.remove("is-done");
+          btn.setAttribute("aria-label", label);
+        }, 1600);
+      });
+    });
+  });
+
   var M = window.Motion;
   if (!M || !M.animate || !M.inView) return;
   if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
@@ -13,10 +31,20 @@
   heroEls.forEach(function (el) { el.style.opacity = "0"; });
   M.animate(
     heroEls,
-    { opacity: [0, 1], transform: ["translateY(14px)", "none"] },
-    { duration: 0.6, ease: EASE, delay: M.stagger(0.09) }
+    { opacity: [0, 1], transform: ["translateY(16px)", "none"] },
+    { duration: 0.65, ease: EASE, delay: M.stagger(0.09) }
   );
 
+  /* 아트워크: 등장 후 느린 부유. 물속이라는 뜻이지 장식 경련이 아니다. */
+  var art = document.querySelector("[data-float]");
+  if (art) {
+    M.animate(art, { opacity: [0, 1], transform: ["scale(0.96)", "scale(1)"] },
+      { duration: 1.1, ease: EASE });
+    M.animate(art,
+      { transform: ["translateY(0)", "translateY(-12px)", "translateY(0)"] },
+      { duration: 9, repeat: Infinity, ease: [0.45, 0, 0.55, 1], delay: 1.1 });
+  }
+
   /* 나머지 섹션: 뷰포트에 들어올 때 한 번씩. */
   var rest = document.querySelectorAll("main > :not(.hero) [data-reveal]");
   rest.forEach(function (el) {
@@ -26,11 +54,11 @@
       function () {
         M.animate(
           el,
-          { opacity: [0, 1], transform: ["translateY(14px)", "none"] },
+          { opacity: [0, 1], transform: ["translateY(16px)", "none"] },
           { duration: 0.55, ease: EASE }
         );
       },
-      { amount: 0.3 }
+      { amount: 0.25 }
     );
   });
 
@@ -45,7 +73,7 @@
         M.animate(
           bars,
           { transform: ["scaleX(0)", "scaleX(1)"] },
-          { duration: 0.8, ease: EASE, delay: M.stagger(0.12) }
+          { duration: 0.85, ease: EASE, delay: M.stagger(0.12) }
         );
       },
       { amount: 0.5 }
diff --git a/docs/templates/landing.html b/docs/templates/landing.html
@@ -1,8 +1,9 @@
 {#- 랜딩. base.html을 상속하지 않는 완전 독립 문서다 — 문서 크롬(마스트헤드·
-    사이드바·검색·테마 토글)이 전부 없다. 테마도 하나로 커밋한다: 이 페이지에는
-    하이라이트된 코드가 없어서 [data-theme] 기계를 얹을 이유가 없다.
+    사이드바·검색·테마 토글)이 전부 없다. 테마는 다크 하나로 커밋한다: 심해
+    발광 콘셉트(오징어 로고 → 먹물 → 심해)의 페이지라 밝은 변형이 없다.
     카피는 전부 front matter의 extra에 있고(양어 파일이 키를 1:1로 가진다),
-    이 파일은 구조만 안다. #}
+    이 파일은 구조만 안다. 아트워크는 손으로 쓴 인라인 SVG — 외부 이미지도,
+    인라인 style도 없다. #}
 {%- set ko = page.language == "ko" %}
 {%- set home = site.base_path ~ ("/ko/" if ko else "/") %}
 <!doctype html>
@@ -34,6 +35,7 @@
 <script src="{{ asset("js/landing.js") }}" defer></script>
 </head>
 <body>
+<div class="specks" aria-hidden="true"></div>
 <a class="skip" href="#main">{{ t("skip_to_content") }}</a>
 
 <header class="topbar">
@@ -43,23 +45,97 @@
   </a>
   <nav class="topnav">
     <a href="{{ home }}start/">{{ t("documentation") }}</a>
+    <a href="{{ home }}benchmark/">{{ page.extra.foot_benchmark }}</a>
+    <span class="langs">
     {%- for lang in page.translations %}
-    <a href="{{ lang.url }}" hreflang="{{ lang.code }}">{{ lang.name }}</a>
+      <a class="lang-pill" href="{{ lang.url }}" hreflang="{{ lang.code }}">{{ lang.code | upper }}</a>
     {%- endfor %}
-    <a href="https://github.com/sqzer-x/sqzass">GitHub</a>
+    </span>
+    <a class="gh" href="https://github.com/sqzer-x/sqzass" aria-label="GitHub" title="GitHub">
+      <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true" focusable="false"><path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
+    </a>
   </nav>
 </header>
 
 <main id="main">
   <section class="hero">
-    <div class="inner">
-      <p class="kicker" data-reveal>{{ page.extra.hero_kicker }}</p>
-      <h1 class="display" data-reveal>{{ page.extra.hero_title_a }} <em>{{ page.extra.hero_title_b }}</em></h1>
-      <p class="sub" data-reveal>{{ page.extra.hero_sub }}</p>
-      <p class="cta" data-reveal>
-        <a class="btn btn-primary" href="{{ home }}start/">{{ page.extra.cta_start }}</a>
-        <a class="btn" href="https://github.com/sqzer-x/sqzass">GitHub</a>
-      </p>
+    <div class="inner hero-grid">
+      <div class="hero-copy">
+        <p class="kicker" data-reveal>
+          <svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2 3 14h7l-1 8 10-12h-7l1-8z"/></svg>
+          {{ page.extra.hero_kicker }}
+        </p>
+        <h1 class="display" data-reveal>{{ page.extra.hero_title_a }}<br><em>{{ page.extra.hero_title_b }}</em></h1>
+        <p class="sub" data-reveal>{{ page.extra.hero_sub }}</p>
+        <p class="cta" data-reveal>
+          <a class="btn btn-primary" href="{{ home }}start/">{{ page.extra.cta_start }}</a>
+          <a class="btn btn-ghost" href="https://github.com/sqzer-x/sqzass">{{ page.extra.cta_github }}</a>
+        </p>
+        <div class="install" data-reveal>
+          <code>$ curl -fsSL {{ site.origin }}{{ site.base_path }}/install.sh | sh</code>
+          <button class="inst-copy" type="button" data-copy-text="curl -fsSL {{ site.origin }}{{ site.base_path }}/install.sh | sh"
+                  aria-label="{{ t("copy") }}" data-copied="{{ t("copied") }}">
+            <svg class="i-copy" viewBox="0 0 24 24" width="15" height="15" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg>
+            <svg class="i-check" viewBox="0 0 24 24" width="15" height="15" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
+          </button>
+        </div>
+      </div>
+
+      {#- 심해 먹물결 아트워크. 장식이므로 보조기기에는 숨긴다. #}
+      <div class="hero-art" aria-hidden="true" data-float>
+        <svg class="art" viewBox="0 0 520 520">
+          <defs>
+            <clipPath id="artclip"><circle cx="260" cy="260" r="238"/></clipPath>
+            <radialGradient id="abg" cx="50%" cy="30%" r="80%">
+              <stop offset="0%" stop-color="#132a4e"/>
+              <stop offset="55%" stop-color="#0b1830"/>
+              <stop offset="100%" stop-color="#060d1a"/>
+            </radialGradient>
+            <radialGradient id="alight" cx="50%" cy="50%" r="50%">
+              <stop offset="0%" stop-color="#59d8ff" stop-opacity="0.55"/>
+              <stop offset="100%" stop-color="#59d8ff" stop-opacity="0"/>
+            </radialGradient>
+            <linearGradient id="w1" x1="0" y1="0" x2="0" y2="1">
+              <stop offset="0%" stop-color="#1c3f6e"/><stop offset="100%" stop-color="#122a4d"/>
+            </linearGradient>
+            <linearGradient id="w2" x1="0" y1="0" x2="0" y2="1">
+              <stop offset="0%" stop-color="#152f56"/><stop offset="100%" stop-color="#0d1f3c"/>
+            </linearGradient>
+            <linearGradient id="w3" x1="0" y1="0" x2="0" y2="1">
+              <stop offset="0%" stop-color="#0f2342"/><stop offset="100%" stop-color="#081228"/>
+            </linearGradient>
+            <linearGradient id="w4" x1="0" y1="0" x2="0" y2="1">
+              <stop offset="0%" stop-color="#0a1830"/><stop offset="100%" stop-color="#050b16"/>
+            </linearGradient>
+            <filter id="soft" x="-40%" y="-40%" width="180%" height="180%">
+              <feGaussianBlur stdDeviation="6"/>
+            </filter>
+          </defs>
+          <circle cx="260" cy="260" r="238" fill="url(#abg)"/>
+          <g clip-path="url(#artclip)">
+            <ellipse cx="260" cy="118" rx="150" ry="120" fill="url(#alight)" filter="url(#soft)"/>
+            <path d="M-20 236 C 70 206, 150 268, 250 240 S 430 196, 540 244 L 540 560 L -20 560 Z" fill="url(#w1)"/>
+            <path d="M-20 232 C 70 202, 150 264, 250 236 S 430 192, 540 240" fill="none" stroke="#6fd8ff" stroke-opacity="0.65" stroke-width="2.5"/>
+            <path d="M-20 302 C 90 272, 180 330, 280 304 S 450 262, 540 306 L 540 560 L -20 560 Z" fill="url(#w2)"/>
+            <path d="M-20 298 C 90 268, 180 326, 280 300 S 450 258, 540 302" fill="none" stroke="#4fb6f5" stroke-opacity="0.4" stroke-width="2"/>
+            <path d="M-20 372 C 80 346, 170 398, 270 374 S 440 336, 540 376 L 540 560 L -20 560 Z" fill="url(#w3)"/>
+            <path d="M-20 368 C 80 342, 170 394, 270 370 S 440 332, 540 372" fill="none" stroke="#3b86d8" stroke-opacity="0.3" stroke-width="1.8"/>
+            <path d="M-20 442 C 90 420, 190 462, 290 444 S 460 414, 540 446 L 540 560 L -20 560 Z" fill="url(#w4)"/>
+            <circle cx="150" cy="160" r="2.4" fill="#8fe5ff" fill-opacity="0.9"/>
+            <circle cx="196" cy="120" r="1.6" fill="#8fe5ff" fill-opacity="0.7"/>
+            <circle cx="330" cy="146" r="2" fill="#8fe5ff" fill-opacity="0.8"/>
+            <circle cx="382" cy="190" r="1.4" fill="#8fe5ff" fill-opacity="0.6"/>
+            <circle cx="256" cy="86" r="1.8" fill="#c9f2ff" fill-opacity="0.9"/>
+            <circle cx="110" cy="210" r="1.3" fill="#8fe5ff" fill-opacity="0.5"/>
+            <circle cx="420" cy="130" r="1.6" fill="#8fe5ff" fill-opacity="0.6"/>
+            <circle cx="150" cy="160" r="7" fill="#59d8ff" fill-opacity="0.25" filter="url(#soft)"/>
+            <circle cx="330" cy="146" r="6" fill="#59d8ff" fill-opacity="0.22" filter="url(#soft)"/>
+            <circle cx="256" cy="86" r="6" fill="#59d8ff" fill-opacity="0.25" filter="url(#soft)"/>
+          </g>
+          <circle cx="260" cy="260" r="238" fill="none" stroke="#9fc8ff" stroke-opacity="0.16" stroke-width="1.5"/>
+          <circle cx="260" cy="260" r="252" fill="none" stroke="#9fc8ff" stroke-opacity="0.07" stroke-width="1"/>
+        </svg>
+      </div>
     </div>
   </section>
 
@@ -72,31 +148,33 @@
   <section class="band bench" aria-labelledby="bench-h">
     <div class="inner">
       <h2 id="bench-h" data-reveal>{{ page.extra.bench_title }}</h2>
-      <p class="bench-note" data-reveal>{{ page.extra.bench_note }}</p>
-      {%- for row in page.extra.bench %}
-      <div class="row" data-reveal>
-        <h3>{{ row.label }}</h3>
-        <div class="meas us">
-          <span class="who">sqzass</span>
-          <svg class="track" aria-hidden="true" preserveAspectRatio="none">
-            <rect class="fill" data-bar width="{{ row.us_w }}" height="100%" rx="2"></rect>
-          </svg>
-          <span class="val">{{ row.us_ms }} ms</span>
-        </div>
-        <div class="meas">
-          <span class="who">Hugo</span>
-          <svg class="track" aria-hidden="true" preserveAspectRatio="none">
-            <rect class="fill" data-bar width="{{ row.them_w }}" height="100%" rx="2"></rect>
-          </svg>
-          <span class="val">{{ row.them_ms }} ms</span>
+      <p class="band-note" data-reveal>{{ page.extra.bench_note }}</p>
+      <div class="bench-card" data-reveal>
+        {%- for row in page.extra.bench %}
+        <div class="row">
+          <h3>{{ row.label }}</h3>
+          <div class="meas us">
+            <span class="who">sqzass</span>
+            <svg class="track" aria-hidden="true" preserveAspectRatio="none">
+              <rect class="fill" data-bar width="{{ row.us_w }}" height="100%" rx="3"></rect>
+            </svg>
+            <span class="val">{{ row.us_ms }} ms</span>
+          </div>
+          <div class="meas">
+            <span class="who">Hugo</span>
+            <svg class="track" aria-hidden="true" preserveAspectRatio="none">
+              <rect class="fill" data-bar width="{{ row.them_w }}" height="100%" rx="3"></rect>
+            </svg>
+            <span class="val">{{ row.them_ms }} ms</span>
+          </div>
         </div>
+        {%- endfor %}
+        <p class="zero">
+          <span class="zero-num">0</span>
+          <span class="zero-label">{{ page.extra.zero_label }}</span>
+        </p>
       </div>
-      {%- endfor %}
-      <p class="zero" data-reveal>
-        <span class="zero-num">0</span>
-        <span class="zero-label">{{ page.extra.zero_label }}</span>
-      </p>
-      <p class="bench-more" data-reveal><a href="{{ home }}benchmark/">{{ page.extra.bench_more }}</a></p>
+      <p class="band-more" data-reveal><a href="{{ home }}benchmark/">{{ page.extra.bench_more }}</a></p>
     </div>
   </section>
 
@@ -111,25 +189,26 @@
         </li>
         {%- endfor %}
       </ul>
-      <p class="more" data-reveal><a href="{{ home }}start/">{{ page.extra.features_more }}</a></p>
+      <p class="band-more" data-reveal><a href="{{ home }}start/">{{ page.extra.features_more }}</a></p>
     </div>
   </section>
 
   <section class="band quick" aria-labelledby="quick-h">
     <div class="inner">
       <h2 id="quick-h" data-reveal>{{ page.extra.quick_title }}</h2>
-      <div class="steps">
-        <div class="step" data-reveal>
-          <h3>{{ page.extra.quick_install }}</h3>
-          <pre><code>curl -fsSL {{ site.origin }}{{ site.base_path }}/install.sh | sh</code></pre>
-          <pre><code>cargo install --git https://github.com/sqzer-x/sqzass</code></pre>
-        </div>
-        <div class="step" data-reveal>
-          <h3>{{ page.extra.quick_use }}</h3>
-          <pre><code>sqzass init my-site &amp;&amp; sqzass serve -i my-site</code></pre>
-        </div>
+      <div class="term" data-reveal>
+        <div class="term-bar" aria-hidden="true"><i></i><i></i><i></i></div>
+        {#- 아래 출력 줄들은 전부 실행 결과 원문이다. 지어낸 줄이 없다. #}
+        <pre><code><span class="t-p">$</span> curl -fsSL {{ site.origin }}{{ site.base_path }}/install.sh | sh
+<span class="t-o">설치했습니다: /usr/local/bin/sqzass (sqzass 0.1.0)</span>
+<span class="t-p">$</span> sqzass init demo
+<span class="t-o">  demo/sqzass.toml
+  demo/content/_index.md
+  demo/templates/page.html</span>
+<span class="t-p">$</span> sqzass build -i demo
+<span class="t-o">1 pages → demo/public</span></code></pre>
       </div>
-      <p class="quick-note" data-reveal>{{ page.extra.quick_note }} <a href="{{ home }}start/installation/">{{ page.extra.quick_note_link }}</a></p>
+      <p class="band-note quick-note" data-reveal>{{ page.extra.quick_note }} <a href="{{ home }}start/installation/">{{ page.extra.quick_note_link }}</a></p>
     </div>
   </section>