feat(showcase): 신규 쇼케이스 3종 — RFS · 트웬티온스 · 새벽청과
Some checks failed
ci / build (push) Failing after 1m52s

각 워크를 서로 다른 클라이언트로 보고 0~6단계를 따로 돌았다(토큰 체계 신규 정의 =
전체 경로). 셋 모두 라이트/다크 반전을 .band-light / .band-dark 가 --band-* 를
재정의하는 규칙으로 정의해 하드 게이트 4를 통과시켰다 — 반전이 섹션마다의 기분이
아니라 두 클래스가 만드는 규칙이다.

RFS — 실시간 유체 시뮬레이터 (rfs-cfd)
  프리셋 darkroom-spec · 컨셉 "암실과 사양서"
  R1 luminary.ai · R2 teenage.engineering EP-133 · 보조 simscale.com (전부 실측)
  히어로에서 브라우저가 실제로 Navier–Stokes 를 푼다. 순수 WebGL2, three.js 미사용.
  이류 → 온도 소스 → 부력·설비 힘 → 발산 → 압력 Jacobi → 투영 → 파티클 전진.
  격자 224×126 / 파티클 26,000 / Jacobi 22회, 좁은 화면은 절반으로 줄인다.
  prefers-reduced-motion 이면 시작하지 않고 그 자리에 RFS 실물 파티클 렌더가 남는다.
  단위계로 세 번 실패했다: dt 를 프레임 단위로 넘겨 파티클이 0.2초 만에 소멸했고,
  전부 급기구에서만 재생성해 실 한 가닥이 됐으며, 랙이 위로 뿜어 핫/콜드 아일이
  갈라지지 않았다. dt 를 초로 못박고 속도를 초당 격자 셀로 통일해 해결했다.
  수치는 전부 RFS 저장소 README 출처. 정확도 지표는 싣지 않았다 — 사내 검증 자료이고
  현재 통과 상태가 아니다.

트웬티온스 (twentyoz-corp)
  프리셋 field-record · 컨셉 "네 개의 현장"
  R1 samsara.com · R2 lars-mueller-publishers.com · R3 = 현행 twentyoz.kr 감사
  현행 사이트 실측: 대비 실패 172개 요소(9~11px 가 3.61:1), 한글 폰트 미지정으로
  한글이 시스템 기본으로 떨어짐, h1 자간 −0.06em(한글 상한의 세 배), 배경 #020202.
  'Digital Genetics' 은유가 산업용 IoT 사업을 가리고 있었다.
  유지한 자산은 radius 0 과 무채색·모노 기조.
  첫 화면에 회사 이름 대신 현장 선택기를 뒀다 — 라디오 그룹이라 JS 0바이트이고
  좌우 화살표 키가 그냥 먹는다. 파트너 19곳은 원본에 도메인 표기가 없어 나누지 않았다.

새벽청과 (saebyeok-cheonggwa)
  프리셋 market-board · 컨셉 "오늘 새벽 두 시의 값"
  R1 natoora.com · R2 phillips.com · R3 제철 12개월 띠
  커머스가 감추는 시세 변동을 히어로의 주인공으로 삼았다. 상품 사진은 아래로 내렸다.
  경매 시각·경락가격·등급·당도 표시 규정을 조사해 카피의 근거로 썼다.
  무화과 당도를 "—" 로 두고 값이 없는 게 아니라 표시가 허용되지 않는 품목이라고 적었다.
  등락은 색이 아니라 ▲▼보합 기호가 먼저다.
  표의 숫자가 예시임을 판 아래와 푸터 두 곳에 명시하고, 주소·전화는 비웠다(게이트 11).
  사진 4장은 codex 내장 image_gen 생성물이며 합계 341KB.

검증: Astro 빌드 통과, verify 체인 L0~L6 10계층 전부 통과,
showcase-audit 신규 3종 12/12 통과(320/390/768/1440).
성능 실측(RFS): JS 24KB · 총 704KB. 폰트만 530KB 로 예산(200KB) 초과 —
한글 웹폰트 자체가 원인이고 기존 cheongon-care 는 650KB 로 더 크다.
저장소 공통 baseline 이라 이번 판은 기록만 남기고 넘어간다.

기존 16종에서 발견된 70건(대비 미달·히어로 줄 수 초과)은 이번 범위를 넘어
design.md 에 목록만 남겼다.
This commit is contained in:
Yun Chan 2026-08-24 12:51:48 +09:00
parent 123d9fc5a8
commit 4d813420dc
31 changed files with 5973 additions and 11 deletions

View file

@ -0,0 +1,643 @@
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>트웬티온스 — 네 개의 현장에서 돌아가는 소프트웨어</title>
<meta
name="description"
content="2020년 설립. 가상현실·산업용 IoT·이커머스 솔루션 전문 기업. VIVEN·EduBill·XD Hub·XD Works 네 개의 자체 제품이 강의실, 데이터센터, 공공기관, 공장 현장에서 돌아간다."
/>
<meta property="og:title" content="트웬티온스 — 네 개의 현장" />
<meta
property="og:description"
content="회사 소개 대신 한 일을 앞에 둔다. 6년 159건, 자체 제품 4종."
/>
<meta property="og:type" content="website" />
<meta name="theme-color" content="#fafaf8" />
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css"
/>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap"
/>
<link rel="stylesheet" href="./styles/main.css" />
<link
rel="icon"
href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23111214'/%3E%3Ctext x='16' y='22' font-family='monospace' font-size='15' font-weight='700' fill='%23FAFAF8' text-anchor='middle'%3E20%3C/text%3E%3C/svg%3E"
/>
</head>
<body>
<a class="skip-link" href="#main">본문으로 건너뛰기</a>
<header class="site-head">
<div class="wrap head-inner">
<a class="wordmark" href="#top">
<span class="wordmark-badge mono" aria-hidden="true">20</span>
<span>트웬티온스</span>
</a>
<nav class="nav" aria-label="주요 섹션">
<a href="#products">제품</a>
<a href="#ledger">한 일</a>
<a href="#record">기록</a>
<a href="#contact">연락</a>
</nav>
<p class="head-meta mono">EST. 2020</p>
</div>
</header>
<main id="main">
<!-- ══════════════════════════════════════════════════════════
1 · 히어로 = 현장 선택기.
회사 이름과 슬로건을 첫 화면에 두지 않는다 — 감수한 리스크다
══════════════════════════════════════════════════════════ -->
<section class="band band-light hero" id="top" aria-labelledby="heroHeading">
<div class="wrap">
<h1 id="heroHeading">
네 개의 현장에서<br />
돌아가고 있다
</h1>
<p class="hero-lead">
트웬티온스는 2020년 1월에 세운 가상현실·산업용 IoT·이커머스 솔루션 회사입니다.
어느 현장의 이야기부터 보시겠습니까.
</p>
<form class="fields">
<fieldset>
<legend class="sr-only">현장 고르기</legend>
<input type="radio" name="field" id="field-edu" class="field-radio" checked />
<input type="radio" name="field" id="field-dc" class="field-radio" />
<input type="radio" name="field" id="field-gov" class="field-radio" />
<input type="radio" name="field" id="field-plant" class="field-radio" />
<div class="field-tabs">
<label for="field-edu">
<span class="tab-num mono">01</span>
<span class="tab-name">강의실과 훈련장</span>
</label>
<label for="field-dc">
<span class="tab-num mono">02</span>
<span class="tab-name">데이터센터와 발전소</span>
</label>
<label for="field-gov">
<span class="tab-num mono">03</span>
<span class="tab-name">공공기관과 대학 행정</span>
</label>
<label for="field-plant">
<span class="tab-num mono">04</span>
<span class="tab-name">공장과 설비 현장</span>
</label>
</div>
<div class="field-panels">
<article class="field-panel" data-panel="edu">
<p class="panel-what">
헤드셋을 쓴 학생이 실습을 하고, 강사는 그 장면을 밖에서 본다.
캐릭터의 몸짓은 웹캠 한 대로 잡는다.
</p>
<dl class="panel-facts">
<div>
<dt>제품</dt>
<dd><strong>VIVEN</strong> — 몰입형 VR 교육·훈련 플랫폼</dd>
</div>
<div>
<dt>기술</dt>
<dd class="mono">Unity3D × WebXR × MediaPipe</dd>
</div>
<div>
<dt>특징</dt>
<dd>PC VMC · Mobile VMC 모듈로 캐릭터 실시간 모션캡처</dd>
</div>
<div>
<dt>납품 사례</dt>
<dd>미래기술학교 운영 (2024) · 메타버스 기반 교육 플랫폼</dd>
</div>
<div>
<dt>성숙도</dt>
<dd class="mono">TRL 9 · 2021 – 현재</dd>
</div>
</dl>
</article>
<article class="field-panel" data-panel="dc">
<p class="panel-what">
설비 여섯 종류가 각자의 프로토콜로 떠드는 것을 한 엔진이 받아
같은 시간축에 올린다. 그 위에서 운전이 자동으로 돈다.
</p>
<dl class="panel-facts">
<div>
<dt>제품</dt>
<dd>
<strong>XD Hub</strong> — 산업용 IoT 데이터 통합 엔진<br />
<strong>XD Works</strong> — DCIM · FEMS 통합 운영 애플리케이션
</dd>
</div>
<div>
<dt>기술</dt>
<dd class="mono">
Java Spring Boot × Netty × TimescaleDB<br />
Spring Boot × NestJS × TypeScript
</dd>
</div>
<div>
<dt>특징</dt>
<dd>6종 산업 프로토콜을 단일 엔진으로 수집·전처리·전송</dd>
</div>
<div>
<dt>납품 사례</dt>
<dd>
과천 데이터 센터 · LS 일렉 청주 FEMS · 제주 폐기물 EMS ·
비금도 EMS · 한유 AFIMS (모두 2024)
</dd>
</div>
<div>
<dt>성숙도</dt>
<dd class="mono">TRL 8 · 2022 – 현재</dd>
</div>
</dl>
</article>
<article class="field-panel" data-panel="gov">
<p class="panel-what">
해외 AI 서비스를 쓰고 싶은데 법인카드도 세금계산서도 안 되는 기관이 있다.
그 사이에 들어가 원화 결제와 증빙을 대신한다.
</p>
<dl class="panel-facts">
<div>
<dt>제품</dt>
<dd><strong>EduBill</strong> — AI SaaS 구독 대행 플랫폼</dd>
</div>
<div>
<dt>기술</dt>
<dd class="mono">Next.js × TypeScript × Supabase PostgreSQL</dd>
</div>
<div>
<dt>쓰는 곳</dt>
<dd>공공기관 · 대학 · 초중고 · 기업 HRD</dd>
</div>
<div>
<dt>납품 사례</dt>
<dd>KDIS EAI (2024) · EduBill (2024)</dd>
</div>
<div>
<dt>성숙도</dt>
<dd class="mono">TRL 8 · 2024 – 현재</dd>
</div>
</dl>
</article>
<article class="field-panel" data-panel="plant">
<p class="panel-what">
현장에서는 사무실 화면이 안 열린다. 장갑 낀 손과 밝은 햇빛,
끊기는 통신을 전제로 다시 만든다.
</p>
<dl class="panel-facts">
<div>
<dt>성격</dt>
<dd>고객사 설비·공정에 맞춰 짓는 현장 애플리케이션</dd>
</div>
<div>
<dt>납품 사례</dt>
<dd>
브래키츠 BSLIM · 영진EL 2.0 스마트 APP · LS 전선 부스덕트 (모두 2024)
</dd>
</div>
<div>
<dt>기술</dt>
<dd class="mono">Spring Boot / PostgreSQL / WebSocket · Vue3</dd>
</div>
<div>
<dt>가장 무거운 것</dt>
<dd>
ACS (Auto Control System) — Unity Engine · RFS 실시간 유체 시뮬레이션 ·
Transformer 기반 AI (2024)
</dd>
</div>
</dl>
</article>
</div>
</fieldset>
</form>
</div>
</section>
<!-- ══════════════════════════════════════════════════════════
2 · 회사
══════════════════════════════════════════════════════════ -->
<section class="band band-light section-about" id="about" aria-labelledby="aboutHeading">
<div class="wrap split">
<div class="split-lead">
<h2 id="aboutHeading">여섯 해 동안 쌓인 것</h2>
</div>
<div class="split-body">
<p class="lead">
서로 다른 산업의 프로젝트 경험과 새 기술을 붙여, 고객이 다음 성장 동력을 찾도록
돕는 것이 하는 일입니다. 에너지, 건물 자동화, 헬스케어처럼 틀리면 곤란한 영역이
주 무대입니다.
</p>
<dl class="counts">
<div>
<dt>수행 프로젝트</dt>
<dd class="mono">159<span>건</span></dd>
</div>
<div>
<dt>고객사</dt>
<dd class="mono">42<span>곳</span></dd>
</div>
<div>
<dt>구성원</dt>
<dd class="mono">40<span>명</span></dd>
</div>
<div>
<dt>특허</dt>
<dd class="mono">4<span>건</span></dd>
</div>
</dl>
<p class="counts-note">
위 넷은 회사가 공개한 값입니다. 아래 <a href="#ledger">한 일</a> 목록에는
그중 공개 가능한 49건의 일부를 이름·연도·기술 스택과 함께 적었습니다.
</p>
</div>
</div>
</section>
<!-- ══════════════════════════════════════════════════════════
3 · 제품 — 반전 밴드. 제품은 기계다
══════════════════════════════════════════════════════════ -->
<section class="band band-dark section-products" id="products" aria-labelledby="prodHeading">
<div class="wrap">
<p class="eyebrow">자체 제품</p>
<h2 id="prodHeading">팔러 다니는 것이 아니라 계속 고치는 것</h2>
<p class="section-lead">
네 개 모두 특정 고객의 요구에서 시작해 제품이 됐습니다. 지금도 각자의 개발 주기가
돌아가고 있습니다.
</p>
<ol class="product-list">
<li>
<p class="prod-id mono">V–01</p>
<div class="prod-body">
<h3>VIVEN <span class="prod-kind">메타버스 플랫폼</span></h3>
<p>
기업과 교육기관을 위한 몰입형 VR 교육·훈련 플랫폼. PC VMC 와 Mobile VMC
모듈로 캐릭터 실시간 모션캡처를 지원합니다.
</p>
<p class="prod-stack mono">Unity3D × WebXR × MediaPipe</p>
</div>
<dl class="prod-meta mono">
<div><dt>규모</dt><dd>Enterprise</dd></div>
<div><dt>주기</dt><dd>2021 –</dd></div>
<div><dt>성숙도</dt><dd>TRL 9</dd></div>
</dl>
</li>
<li>
<p class="prod-id mono">V–02</p>
<div class="prod-body">
<h3>EduBill <span class="prod-kind">교육 SaaS</span></h3>
<p>
공공기관·대학·초중고·기업 HRD 를 위한 AI SaaS 구독 대행 플랫폼.
해외 AI 서비스를 원화 결제와 세금계산서 발행으로 들여옵니다.
</p>
<p class="prod-stack mono">Next.js × TypeScript × Supabase PostgreSQL</p>
</div>
<dl class="prod-meta mono">
<div><dt>규모</dt><dd>B2G · 교육</dd></div>
<div><dt>주기</dt><dd>2024 –</dd></div>
<div><dt>성숙도</dt><dd>TRL 8</dd></div>
</dl>
</li>
<li>
<p class="prod-id mono">V–03</p>
<div class="prod-body">
<h3>XD Hub <span class="prod-kind">산업용 IoT</span></h3>
<p>
데이터센터·제조·에너지·빌딩 도메인을 위한 산업용 IoT 데이터 통합 엔진.
6종 산업 프로토콜을 단일 엔진으로 수집·전처리·전송합니다.
</p>
<p class="prod-stack mono">Java Spring Boot × Netty × TimescaleDB</p>
</div>
<dl class="prod-meta mono">
<div><dt>규모</dt><dd>설비</dd></div>
<div><dt>주기</dt><dd>2022 –</dd></div>
<div><dt>성숙도</dt><dd>TRL 8</dd></div>
</dl>
</li>
<li>
<p class="prod-id mono">V–04</p>
<div class="prod-body">
<h3>XD Works <span class="prod-kind">DCIM · FEMS</span></h3>
<p>
XD Hub 가 모은 데이터를 받아 데이터센터 코로케이션, 빌딩, 공장, 발전소의
운영을 자동화하는 통합 운영 애플리케이션입니다.
</p>
<p class="prod-stack mono">Spring Boot × NestJS × TypeScript</p>
</div>
<dl class="prod-meta mono">
<div><dt>규모</dt><dd>설비 · B2B</dd></div>
<div><dt>주기</dt><dd>2023 –</dd></div>
<div><dt>성숙도</dt><dd>TRL 8</dd></div>
</dl>
</li>
</ol>
</div>
</section>
<!-- ══════════════════════════════════════════════════════════
4 · 한 일 — 프로젝트 원장
══════════════════════════════════════════════════════════ -->
<section class="band band-light section-ledger" id="ledger" aria-labelledby="ledgerHeading">
<div class="wrap">
<h2 id="ledgerHeading">한 일</h2>
<p class="section-lead">
공개 가능한 49건 가운데 12건입니다. 회사 소개서에 쓰는 문장 대신 이름과 연도,
그리고 무엇으로 만들었는지를 적습니다.
</p>
<table class="ledger">
<caption class="sr-only">트웬티온스 수행 프로젝트 12건 — 이름, 연도, 사용 기술</caption>
<thead>
<tr>
<th scope="col" class="col-id">번호</th>
<th scope="col">프로젝트</th>
<th scope="col" class="col-year">연도</th>
<th scope="col">기술</th>
</tr>
</thead>
<tbody>
<tr>
<td class="mono">001</td>
<th scope="row">EduBill</th>
<td class="mono">2024</td>
<td class="mono">Next.js · TypeScript · Supabase PostgreSQL</td>
</tr>
<tr>
<td class="mono">002</td>
<th scope="row">과천 데이터 센터</th>
<td class="mono">2024</td>
<td class="mono">Vue3 · Spring · PostgreSQL</td>
</tr>
<tr>
<td class="mono">003</td>
<th scope="row">제주 폐기물 EMS</th>
<td class="mono">2024</td>
<td class="mono">Vue3 · Spring · PostgreSQL</td>
</tr>
<tr>
<td class="mono">004</td>
<th scope="row">KDIS EAI</th>
<td class="mono">2024</td>
<td class="mono">Vue3 · Spring · PostgreSQL</td>
</tr>
<tr>
<td class="mono">005</td>
<th scope="row">LS 일렉 청주 FEMS</th>
<td class="mono">2024</td>
<td class="mono">Vue3 · Spring · PostgreSQL</td>
</tr>
<tr>
<td class="mono">006</td>
<th scope="row">LS 전선 부스덕트</th>
<td class="mono">2024</td>
<td class="mono">Vue3 · Spring · PostgreSQL</td>
</tr>
<tr>
<td class="mono">007</td>
<th scope="row">브래키츠 BSLIM</th>
<td class="mono">2024</td>
<td class="mono">Spring Boot · PostgreSQL · WebSocket</td>
</tr>
<tr>
<td class="mono">008</td>
<th scope="row">영진EL 2.0 스마트 APP</th>
<td class="mono">2024</td>
<td class="mono">Vue3</td>
</tr>
<tr>
<td class="mono">009</td>
<th scope="row">미래기술학교 운영</th>
<td class="mono">2024</td>
<td class="mono">Unity Engine · Blender · Unreal Engine</td>
</tr>
<tr>
<td class="mono">010</td>
<th scope="row">한유 AFIMS</th>
<td class="mono">2024</td>
<td class="mono">Vue3 · Spring · PostgreSQL</td>
</tr>
<tr>
<td class="mono">011</td>
<th scope="row">비금도 EMS</th>
<td class="mono">2024</td>
<td class="mono">Vue3 · Spring · Java</td>
</tr>
<tr class="row-mark">
<td class="mono">012</td>
<th scope="row">ACS (Auto Control System)</th>
<td class="mono">2024</td>
<td class="mono">Unity Engine · RFS 실시간 유체 시뮬레이션 · Transformer 기반 AI</td>
</tr>
</tbody>
</table>
<p class="ledger-note">
마지막 줄이 지금 가장 멀리 가 있는 일입니다. 데이터센터의 공기 흐름을 GPU 위에서
실시간으로 풀어 제어를 검증합니다.
</p>
</div>
</section>
<!-- ══════════════════════════════════════════════════════════
5 · 함께 일한 곳
══════════════════════════════════════════════════════════ -->
<section class="band band-light section-partners" id="partners" aria-labelledby="partnersHeading">
<div class="wrap">
<h2 id="partnersHeading">함께 일한 곳</h2>
<p class="section-lead">
대학과 대기업 설비 부문이 섞여 있습니다. 어느 쪽이든 검수 기준이 까다로운 곳입니다.
</p>
<ul class="partners">
<li>LS SAUTER</li>
<li>경희대학교</li>
<li>SAEKI P&amp;C</li>
<li>KDI School</li>
<li>COSS 사업단</li>
<li>클라우드브릭</li>
<li>한유</li>
<li>게임랩</li>
<li>METANET PLATFORM</li>
<li>안랩</li>
<li>강원대학교</li>
<li>중앙대학교</li>
<li>건국대학교</li>
<li>한화솔루션</li>
<li>가비아</li>
<li>GS칼텍스</li>
<li>SK하이닉스</li>
<li>LG디스플레이</li>
<li>대구한의대학교</li>
</ul>
</div>
</section>
<!-- ══════════════════════════════════════════════════════════
6 · 기록 — 반전 밴드
══════════════════════════════════════════════════════════ -->
<section class="band band-dark section-record" id="record" aria-labelledby="recordHeading">
<div class="wrap">
<p class="eyebrow">최근 기록</p>
<h2 id="recordHeading">밖에서 확인된 것</h2>
<ol class="record-list">
<li>
<p class="rec-date mono">2026.02.24</p>
<div>
<h3>경기우수벤처기업 표창 — 경기지방중소벤처기업청장상</h3>
<p>기술·경영·혁신 능력이 뛰어나고 사회공헌도가 높은 벤처기업으로 인정</p>
</div>
<p class="rec-kind">수상 · 인증</p>
</li>
<li>
<p class="rec-date mono">2026.01.20</p>
<div>
<h3>2025 경기도 일자리 우수기업 인증</h3>
<p>고용증가율 10% 이상, 근무환경과 복리후생 제도 개선으로 인정</p>
</div>
<p class="rec-kind">수상 · 인증</p>
</li>
<li>
<p class="rec-date mono">2025.11.03</p>
<div>
<h3>건국대, 시리아·요르단 교육기관 대표단 방문</h3>
<p>트웬티온스와 함께 개발한 메타버스 기반 교육 플랫폼 시연</p>
</div>
<p class="rec-kind">교육 · 협력</p>
</li>
<li>
<p class="rec-date mono">2025.10.31</p>
<div>
<h3>중동 대표단, X-Space 에서 K-에듀테크 체험</h3>
<p>메타버스 기반 교육 플랫폼 체험과 협력 논의</p>
</div>
<p class="rec-kind">교육 · 협력</p>
</li>
<li>
<p class="rec-date mono">2025.08.19</p>
<div>
<h3>과기정통부 2025 가상융합대학원 성과공유회</h3>
<p>서강대 개최. AI 시대 인재양성 비전 논의에 참여</p>
</div>
<p class="rec-kind">행사</p>
</li>
<li>
<p class="rec-date mono">2025.07.04</p>
<div>
<h3>벤처기업 혁신성장유형 재인증</h3>
<p>기술 중심의 비전과 디지털 혁신 노력을 인정받음</p>
</div>
<p class="rec-kind">수상 · 인증</p>
</li>
</ol>
</div>
</section>
<!-- ══════════════════════════════════════════════════════════
7 · 채용
══════════════════════════════════════════════════════════ -->
<section class="band band-light section-career" id="career" aria-labelledby="careerHeading">
<div class="wrap split">
<div class="split-lead">
<h2 id="careerHeading">지금은 정규 공고가 닫혀 있습니다</h2>
</div>
<div class="split-body">
<p class="lead">
다섯 개 직무가 모두 마감 상태입니다. 닫힌 것을 열려 있는 것처럼 적어 두면
지원하는 쪽의 시간을 뺏게 되므로, 상태를 그대로 적습니다.
</p>
<ul class="jobs">
<li>
<span class="job-name">시니어 소프트웨어 엔지니어</span>
<span class="job-hint">산업용 소프트웨어 · C++ / C# / Python · PLC · HMI · SCADA</span>
<span class="job-state mono">마감</span>
</li>
<li>
<span class="job-name">DevOps 엔지니어</span>
<span class="job-hint">컨테이너 · 오케스트레이션 · CI/CD · IaC</span>
<span class="job-state mono">마감</span>
</li>
<li>
<span class="job-name">프로덕트 매니저</span>
<span class="job-hint">IT 서비스 기획·운영 3년 이상 · 데이터 기반 의사결정</span>
<span class="job-state mono">마감</span>
</li>
<li>
<span class="job-name">서비스 기획자</span>
<span class="job-hint">UI/UX 기획 · 와이어프레임 · 애자일 / 스크럼</span>
<span class="job-state mono">마감</span>
</li>
<li>
<span class="job-name">UI/UX 디자이너</span>
<span class="job-hint">Figma · 웹 / 모바일 포트폴리오 · 사용자 중심 설계</span>
<span class="job-state mono">마감</span>
</li>
</ul>
<p class="jobs-open">
공고와 무관하게 이야기를 시작할 수는 있습니다.
<a href="mailto:hello@twentyoz.kr?subject=%EC%B1%84%EC%9A%A9%20%EB%AC%B8%EC%9D%98">채용 문의 보내기</a>
</p>
</div>
</div>
</section>
<!-- ══════════════════════════════════════════════════════════
8 · 연락
══════════════════════════════════════════════════════════ -->
<section class="band band-light section-contact" id="contact" aria-labelledby="contactHeading">
<div class="wrap split">
<div class="split-lead">
<h2 id="contactHeading">연락</h2>
</div>
<div class="split-body">
<dl class="contact-rows">
<div>
<dt>주소</dt>
<dd>경기도 화성시 동탄첨단산업1로 27, A909호<br />(영천동, 금강펜테리움 IX 타워)</dd>
</div>
<div>
<dt>전화</dt>
<dd><a class="mono" href="tel:+8207043531190">070-4353-1190</a></dd>
</div>
<div>
<dt>메일</dt>
<dd><a class="mono" href="mailto:hello@twentyoz.kr">hello@twentyoz.kr</a></dd>
</div>
<div>
<dt>설립</dt>
<dd class="mono">2020년 1월</dd>
</div>
</dl>
<a class="btn" href="mailto:hello@twentyoz.kr?subject=%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%20%EB%AC%B8%EC%9D%98">
프로젝트 문의
</a>
</div>
</div>
</section>
</main>
<footer class="band band-dark site-foot">
<div class="wrap foot-inner">
<p class="foot-name">트웬티온스 · TWENTYOZ</p>
<p class="foot-line">
가상현실 · 산업용 IoT · 이커머스 솔루션 · 경기도 화성시 동탄
</p>
<p class="foot-fine">© 2020–2026 TWENTYOZ</p>
</div>
</footer>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View file

@ -0,0 +1,842 @@
@import "./tokens.css";
/* ==========================================================================
트웬티온스 — 메인 스타일시트
현행 사이트는 순흑 한 겹이라 무엇이 중요한지 알 수 없었다. 종이를 기본으로
뒤집고, 반전(잉크) 밴드는 '기계'를 다루는 두 섹션(제품·기록)에만 쓴다.
반전은 아래 두 클래스가 토큰을 재정의하는 규칙이다 — 섹션마다 기분대로가 아니다.
========================================================================== */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 16px;
scroll-behavior: smooth;
overflow-x: hidden;
background: var(--surface);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
min-height: 100dvh;
font-family: var(--font-body);
font-size: var(--step-0);
line-height: var(--leading-normal);
background: var(--surface);
color: var(--ink);
word-break: keep-all;
overflow-wrap: break-word;
overflow-x: hidden;
}
img,
svg {
display: block;
max-width: 100%;
}
a {
color: inherit;
}
button,
input,
select,
textarea {
font: inherit;
color: inherit;
}
fieldset {
border: 0;
}
h1,
h2,
h3 {
font-weight: 600;
line-height: var(--leading-tight);
letter-spacing: -0.015em; /* 현행 사이트의 −0.06em 은 한글 상한의 세 배였다 */
text-wrap: balance;
}
.mono {
font-family: var(--font-mono);
font-variant-numeric: tabular-nums;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.wrap {
width: min(100% - 2 * var(--pad-inline), var(--container));
margin-inline: auto;
}
/* ── 두 체제 ────────────────────────────────────────────────────── */
.band-light {
--band-surface: var(--surface);
--band-surface-2: var(--surface-2);
--band-surface-3: var(--surface-3);
--band-line: var(--line);
--band-line-strong: var(--line-strong);
--band-ink: var(--ink);
--band-ink-muted: var(--ink-muted);
--band-ink-faint: var(--ink-faint);
--band-accent: var(--accent);
--band-accent-hover: var(--accent-hover);
--band-accent-ink: var(--accent-ink);
--band-accent-wash: var(--accent-wash);
}
.band-dark {
--band-surface: var(--dark-surface);
--band-surface-2: var(--dark-surface-2);
--band-surface-3: var(--dark-surface-3);
--band-line: var(--dark-line);
--band-line-strong: var(--dark-line-strong);
--band-ink: var(--dark-ink);
--band-ink-muted: var(--dark-ink-muted);
--band-ink-faint: var(--dark-ink-faint);
--band-accent: var(--dark-accent);
--band-accent-hover: var(--dark-accent-hover);
--band-accent-ink: var(--dark-accent-ink);
--band-accent-wash: var(--dark-accent-wash);
}
.band {
position: relative;
background: var(--band-surface);
color: var(--band-ink);
}
.band > .wrap {
padding-block: var(--space-8);
}
/* ── 접근성 ─────────────────────────────────────────────────────── */
.skip-link {
position: fixed;
top: var(--space-3);
left: var(--space-3);
z-index: 200;
padding: var(--space-2) var(--space-3);
background: var(--ink);
color: var(--surface);
text-decoration: none;
transform: translateY(-250%);
transition: transform var(--dur-quick) var(--ease);
}
.skip-link:focus-visible {
transform: translateY(0);
}
:where(a, button, input, label, [tabindex]):focus-visible {
outline: 2px solid var(--band-accent, var(--accent));
outline-offset: 3px;
}
/* ── 헤더 ───────────────────────────────────────────────────────── */
.site-head {
position: sticky;
top: 0;
z-index: 100;
background: var(--surface);
border-bottom: 1px solid var(--line-strong);
}
.head-inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-3);
min-height: 56px;
min-width: 0;
}
.wordmark {
display: inline-flex;
align-items: center;
gap: var(--space-2);
font-weight: 600;
text-decoration: none;
white-space: nowrap;
flex-shrink: 0;
}
.wordmark-badge {
display: inline-grid;
place-items: center;
width: 26px;
height: 26px;
background: var(--ink);
color: var(--surface);
font-size: 0.75rem;
font-weight: 700;
}
.nav {
display: flex;
gap: clamp(var(--space-3), 2.4vw, var(--space-5));
min-width: 0;
}
.nav a {
color: var(--ink-muted);
font-size: var(--step--1);
text-decoration: none;
white-space: nowrap;
padding-block: var(--space-2);
transition: color var(--dur-quick) var(--ease);
}
.nav a:hover {
color: var(--accent);
}
.head-meta {
font-size: var(--step--1);
color: var(--ink-faint);
white-space: nowrap;
flex-shrink: 0;
}
/* ── 히어로 ─────────────────────────────────────────────────────── */
.hero h1 {
font-size: var(--display);
max-width: 16ch;
}
.hero-lead {
margin-top: var(--space-4);
max-width: var(--measure);
font-size: var(--step-1);
color: var(--band-ink-muted);
line-height: var(--leading-loose);
}
/* ── 현장 선택기 — JS 0바이트. 라디오 그룹이라 좌우 화살표가 그대로 먹는다 ── */
.fields {
margin-top: var(--space-6);
}
.field-radio {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
pointer-events: none;
}
.field-tabs {
display: grid;
border-top: 1px solid var(--line-strong);
border-bottom: 1px solid var(--line);
}
@media (min-width: 720px) {
.field-tabs {
grid-template-columns: repeat(4, 1fr);
}
}
.field-tabs label {
display: block;
padding: var(--space-3) var(--space-3) var(--space-3) 0;
border-bottom: 1px solid var(--line);
cursor: pointer;
color: var(--ink-muted);
transition: color var(--dur-quick) var(--ease);
}
@media (min-width: 720px) {
.field-tabs label {
border-bottom: 0;
border-right: 1px solid var(--line);
padding-right: var(--space-4);
padding-left: var(--space-3);
}
.field-tabs label:first-of-type {
padding-left: 0;
}
.field-tabs label:last-of-type {
border-right: 0;
}
}
.field-tabs label:hover {
color: var(--ink);
}
.tab-num {
display: block;
font-size: var(--step--1);
color: var(--ink-faint);
}
.tab-name {
display: block;
margin-top: var(--space-1);
font-weight: 600;
font-size: var(--step-0);
}
/* 선택 상태 — 라디오가 진실의 원본이다 */
#field-edu:checked ~ .field-tabs label[for="field-edu"],
#field-dc:checked ~ .field-tabs label[for="field-dc"],
#field-gov:checked ~ .field-tabs label[for="field-gov"],
#field-plant:checked ~ .field-tabs label[for="field-plant"] {
color: var(--ink);
box-shadow: inset 0 3px 0 0 var(--accent);
}
#field-edu:checked ~ .field-tabs label[for="field-edu"] .tab-num,
#field-dc:checked ~ .field-tabs label[for="field-dc"] .tab-num,
#field-gov:checked ~ .field-tabs label[for="field-gov"] .tab-num,
#field-plant:checked ~ .field-tabs label[for="field-plant"] .tab-num {
color: var(--accent);
}
.field-radio:focus-visible ~ .field-tabs label[for="field-edu"] {
outline: 2px solid var(--accent);
outline-offset: -2px;
}
.field-panel {
display: none;
padding-top: var(--space-5);
}
#field-edu:checked ~ .field-panels [data-panel="edu"],
#field-dc:checked ~ .field-panels [data-panel="dc"],
#field-gov:checked ~ .field-panels [data-panel="gov"],
#field-plant:checked ~ .field-panels [data-panel="plant"] {
display: block;
}
.panel-what {
font-size: var(--step-1);
max-width: var(--measure);
line-height: var(--leading-loose);
}
.panel-facts {
margin-top: var(--space-5);
border-top: 1px solid var(--line);
}
.panel-facts > div {
display: grid;
gap: var(--space-1) var(--space-4);
padding-block: var(--space-3);
border-bottom: 1px solid var(--line);
}
@media (min-width: 640px) {
.panel-facts > div {
grid-template-columns: 8rem 1fr;
}
}
.panel-facts dt {
font-size: var(--step--1);
color: var(--ink-faint);
}
.panel-facts dd {
color: var(--ink-muted);
line-height: var(--leading-loose);
}
.panel-facts strong {
color: var(--ink);
font-weight: 600;
}
/* ── 섹션 공통 ──────────────────────────────────────────────────── */
.eyebrow {
font-family: var(--font-mono);
font-size: var(--step--1);
color: var(--band-accent);
margin-bottom: var(--space-3);
}
.band h2 {
font-size: var(--step-3);
max-width: 20ch;
}
.section-lead,
.lead {
margin-top: var(--space-4);
max-width: var(--measure);
color: var(--band-ink-muted);
font-size: var(--step-1);
line-height: var(--leading-loose);
}
/* ── 비대칭 2열 ─────────────────────────────────────────────────── */
.split {
display: grid;
gap: var(--space-5);
}
@media (min-width: 900px) {
.split {
grid-template-columns: 4fr 8fr;
gap: var(--space-7);
align-items: start;
}
}
/* ── 수치 ───────────────────────────────────────────────────────── */
.counts {
margin-top: var(--space-6);
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
border-top: 1px solid var(--band-line-strong);
border-left: 1px solid var(--band-line);
}
.counts > div {
padding: var(--space-4);
border-right: 1px solid var(--band-line);
border-bottom: 1px solid var(--band-line);
}
.counts dt {
font-size: var(--step--1);
color: var(--band-ink-faint);
}
.counts dd {
margin-top: var(--space-2);
font-size: var(--step-3);
line-height: 1.05;
letter-spacing: -0.02em;
}
.counts dd span {
font-size: var(--step-0);
color: var(--band-ink-muted);
margin-left: 2px;
}
.counts-note {
margin-top: var(--space-4);
font-size: var(--step--1);
color: var(--band-ink-faint);
line-height: var(--leading-loose);
max-width: var(--measure);
}
.counts-note a {
color: var(--band-accent);
}
/* ── 제품 목록 ──────────────────────────────────────────────────── */
.product-list {
margin-top: var(--space-6);
list-style: none;
border-top: 1px solid var(--band-line-strong);
}
.product-list li {
display: grid;
gap: var(--space-3);
padding-block: var(--space-5);
border-bottom: 1px solid var(--band-line);
}
@media (min-width: 900px) {
.product-list li {
grid-template-columns: 4rem 1fr 11rem;
gap: var(--space-5);
align-items: start;
}
}
.prod-id {
font-size: var(--step--1);
color: var(--band-accent);
}
.prod-body h3 {
font-size: var(--step-2);
display: flex;
align-items: baseline;
gap: var(--space-3);
flex-wrap: wrap;
}
.prod-kind {
font-size: var(--step--1);
font-weight: 400;
color: var(--band-ink-faint);
}
.prod-body p {
margin-top: var(--space-3);
color: var(--band-ink-muted);
max-width: 46ch;
line-height: var(--leading-loose);
}
.prod-stack {
font-size: var(--step--1);
color: var(--band-ink-faint);
}
.prod-meta {
font-size: var(--step--1);
display: grid;
gap: var(--space-2);
align-content: start;
}
.prod-meta > div {
display: grid;
grid-template-columns: 4rem 1fr;
gap: var(--space-2);
}
.prod-meta dt {
color: var(--band-ink-faint);
}
.prod-meta dd {
color: var(--band-ink-muted);
}
/* ── 원장 표 ────────────────────────────────────────────────────── */
.ledger {
margin-top: var(--space-6);
width: 100%;
border-collapse: collapse;
font-size: var(--step--1);
text-align: left;
}
.ledger th,
.ledger td {
padding: var(--space-3) var(--space-3) var(--space-3) 0;
border-bottom: 1px solid var(--band-line);
vertical-align: top;
}
.ledger thead th {
border-bottom: 1px solid var(--band-line-strong);
color: var(--band-ink-faint);
font-weight: 400;
}
.ledger tbody th {
font-weight: 600;
font-size: var(--step-0);
}
.ledger td {
color: var(--band-ink-muted);
}
.col-id {
width: 3.5rem;
}
.col-year {
width: 4rem;
}
.row-mark th,
.row-mark td {
border-bottom: 0;
}
.row-mark th {
color: var(--band-accent);
}
.ledger-note {
margin-top: var(--space-4);
padding-top: var(--space-3);
border-top: 2px solid var(--band-accent);
font-size: var(--step--1);
color: var(--band-ink-muted);
max-width: var(--measure);
line-height: var(--leading-loose);
}
/* ── 파트너 ─────────────────────────────────────────────────────── */
.section-partners {
background: var(--surface-2);
}
.partners {
margin-top: var(--space-6);
list-style: none;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 190px), 1fr));
border-top: 1px solid var(--band-line-strong);
}
.partners li {
padding: var(--space-3) var(--space-3) var(--space-3) 0;
border-bottom: 1px solid var(--band-line);
color: var(--band-ink-muted);
font-size: var(--step--1);
}
/* ── 기록 ───────────────────────────────────────────────────────── */
.record-list {
margin-top: var(--space-6);
list-style: none;
border-top: 1px solid var(--band-line-strong);
}
.record-list li {
display: grid;
gap: var(--space-2);
padding-block: var(--space-4);
border-bottom: 1px solid var(--band-line);
}
@media (min-width: 860px) {
.record-list li {
grid-template-columns: 7rem 1fr 7rem;
gap: var(--space-4);
align-items: baseline;
}
}
.rec-date {
font-size: var(--step--1);
color: var(--band-ink-faint);
}
.record-list h3 {
font-size: var(--step-1);
}
.record-list div p {
margin-top: var(--space-2);
color: var(--band-ink-muted);
font-size: var(--step--1);
line-height: var(--leading-loose);
}
.rec-kind {
font-size: var(--step--1);
color: var(--band-ink-faint);
}
@media (min-width: 860px) {
.rec-kind {
text-align: right;
}
}
/* ── 채용 ───────────────────────────────────────────────────────── */
.jobs {
margin-top: var(--space-5);
list-style: none;
border-top: 1px solid var(--band-line-strong);
}
.jobs li {
display: grid;
gap: var(--space-1) var(--space-4);
padding-block: var(--space-3);
border-bottom: 1px solid var(--band-line);
}
@media (min-width: 720px) {
.jobs li {
grid-template-columns: 14rem 1fr 4rem;
align-items: baseline;
}
}
.job-name {
font-weight: 600;
}
.job-hint {
font-size: var(--step--1);
color: var(--band-ink-muted);
line-height: var(--leading-loose);
}
.job-state {
font-size: var(--step--1);
color: var(--band-ink-faint);
}
@media (min-width: 720px) {
.job-state {
text-align: right;
}
}
.jobs-open {
margin-top: var(--space-4);
font-size: var(--step--1);
color: var(--band-ink-muted);
line-height: var(--leading-loose);
}
.jobs-open a {
color: var(--band-accent);
}
/* ── 연락 ───────────────────────────────────────────────────────── */
.contact-rows {
border-top: 1px solid var(--band-line-strong);
}
.contact-rows > div {
display: grid;
gap: var(--space-1) var(--space-4);
padding-block: var(--space-3);
border-bottom: 1px solid var(--band-line);
}
@media (min-width: 640px) {
.contact-rows > div {
grid-template-columns: 6rem 1fr;
}
}
.contact-rows dt {
font-size: var(--step--1);
color: var(--band-ink-faint);
}
.contact-rows dd {
color: var(--band-ink-muted);
line-height: var(--leading-loose);
}
.contact-rows a {
color: var(--band-accent);
}
.btn {
display: inline-block;
margin-top: var(--space-5);
padding: var(--space-3) var(--space-5);
background: var(--band-accent);
color: var(--band-accent-ink);
font-weight: 600;
text-decoration: none;
white-space: nowrap;
transition: background-color var(--dur-quick) var(--ease);
}
.btn:hover {
background: var(--band-accent-hover);
}
/* ── 푸터 ───────────────────────────────────────────────────────── */
.foot-inner {
display: grid;
gap: var(--space-2);
}
.foot-name {
font-weight: 600;
}
.foot-line {
color: var(--band-ink-muted);
font-size: var(--step--1);
}
.foot-fine {
margin-top: var(--space-4);
padding-top: var(--space-3);
border-top: 1px solid var(--band-line);
font-size: var(--step--1);
color: var(--band-ink-faint);
}
/* ── 좁은 화면 ──────────────────────────────────────────────────── */
@media (max-width: 640px) {
.head-inner {
flex-wrap: wrap;
padding-block: var(--space-2);
row-gap: var(--space-2);
}
.nav {
order: 3;
width: 100%;
justify-content: space-between;
gap: var(--space-2);
border-top: 1px solid var(--line);
padding-top: var(--space-2);
}
.head-meta {
display: none;
}
.counts {
grid-template-columns: repeat(2, 1fr);
}
}
/* ── 모션을 줄이는 설정 ─────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* ── 인쇄 — 현장 선택기는 종이에서 의미가 없으므로 네 패널을 모두 편다 ── */
@media print {
.site-head,
.skip-link,
.btn {
display: none;
}
.band {
background: #fff;
color: #000;
}
.field-panel {
display: block !important;
break-inside: avoid;
}
.field-tabs {
display: none;
}
}

View file

@ -0,0 +1,117 @@
/* ==========================================================================
트웬티온스 (TWENTYOZ) — 회사 홈페이지 리디자인 · 디자인 토큰 SSOT
컨셉 : 네 개의 현장 — 회사 소개가 아니라, 같은 기술이 서로 다른 현장에서
무엇을 하고 있는지의 목록이 이 사이트의 본체다
프리셋: field-record (신규 정의. swiss-minimal 을 뼈대로 삼되 본문을 키웠다)
강조색: 신호 적색 1색. 라이트/다크는 규칙으로 정의된 한 쌍이므로 1종으로 센다
── 0단계 감사 · 현행 twentyoz.kr 실측 (2026-08-24, 1249px computed style)
유지할 자산
· radius 0px 742회 — 형태 어휘가 이미 통일돼 있다. 그대로 가져간다
· 무채색 기조와 모노스페이스(JetBrains Mono 356회) — 정밀함의 어휘는 맞다
· 실제 프로젝트 49건 · 파트너 19곳 · 제품 4종의 기술 스택 표기
고쳐야 할 것
· 대비 실패 **172개 요소** — rgb(102,102,102) 가 배경 rgb(2,2,2) 위에서 3.61:1,
그것도 9~11px 로 284곳에 쓰였다. WCAG AA 미달이고 읽기 자체가 어렵다
· font-family 가 Inter 뿐이라 **한글 폰트가 지정돼 있지 않다**.
한국 회사의 한국어 사이트에서 한글이 시스템 기본값으로 떨어진다
· h1 174.86px 에 letter-spacing −10.49px = **−0.06em**. 한글 상한(−0.02em)의 세 배다
· 배경 #020202 — 순흑에 가깝다
· 'Digital Genetics' 은유가 전면에 있다(CULTIVATING · DROPS · Sativa/Indica ·
Germination · Wholesale Desk · ACQUIRE GENETICS · Open Specimens).
SK하이닉스·LG디스플레이·한화솔루션·GS칼텍스에 산업용 IoT 를 파는 회사의
어휘로는 사업을 가린다. 은유를 걷어내고 한 일을 앞에 둔다
── 레퍼런스 실측 (2026-08-24, 1440px)
R1 구조 · samsara.com (커넥티드 오퍼레이션 / 산업 IoT — 같은 업종)
배경 #FFFFFF · FK Grotesk + FK Grotesk Mono 2패밀리
h1 72px/700 · 본문 16px(404회) · 최대 80px ÷ 본문 = 5.0배
radius 0px 2399회 지배 · 강조색 #FEAE0F 이 버튼 1곳
컨테이너 1425 전폭 ↔ 1345 ↔ 427 칼럼 · 섹션 13
→ 가져온 원리: 섹션 제목이 '무엇을 증명하는가'를 직접 말한다
(Proven where it counts / A track record / Proudly rated #1).
B2B 는 주장이 아니라 기록으로 설득한다
→ 안 가져온 것: 전체 대문자 h1 과 대문자 eyebrow 5종(슬롭 지문 2위),
순백·순흑, 섹션 13개, 앰버 pill 버튼
R2 톤 · lars-mueller-publishers.com (출판사 — 다른 업종)
텍스트 #414141 (순흑 아님) · NB Akademie Std 한 패밀리의 두 웨이트
h1 34px/500 · **본문 20px(190회)** · line-height 30px = 1.5
최대 ÷ 본문 = 1.7배 · radius 0px 1709회 지배 · 컨테이너 1240px
→ 가져온 원리: **본문을 크게 쓰고 제목을 작게 둔다.** 위계를 크기 하나로
만들지 않고 여백과 순서로도 만든다. 한 패밀리의 두 웨이트로 절제한다
→ 안 가져온 것: 강조색 #542BFF(보라 계열 — 슬롭 지문),
최대÷본문 1.7배(평평한 스케일은 안티패턴)
두 레퍼런스의 합성: 본문은 R2 쪽으로 키우고(17px), 최대÷본문은 R1 쪽으로
벌린다(4.0배). 한쪽만 따르면 평평하거나 본문이 작아진다.
========================================================================== */
:root {
/* ── 타이포그래피 — 5단계 + 스케일 밖 디스플레이 1개 ── */
--step--1: 0.8125rem; /* 13px — 표 머리·메타 */
--step-0: 1.0625rem; /* 17px — 본문. R2 의 큰 본문을 한글에 맞춰 옮겼다 */
--step-1: 1.25rem; /* 20px — 리드 */
--step-2: clamp(1.375rem, 1.15rem + 1.1vw, 1.9375rem); /* 22 → 31px */
--step-3: clamp(1.75rem, 1.25rem + 2.5vw, 2.875rem); /* 28 → 46px */
--display: clamp(2.25rem, 1.3rem + 4.6vw, 4.25rem); /* 36 → 68px */
/* 최대 ÷ 본문 = 68 ÷ 17 = 4.0배 */
--leading-tight: 1.2;
--leading-normal: 1.7;
--leading-loose: 1.85;
--measure: 33em;
--font-body: Pretendard, "Pretendard Variable", -apple-system, system-ui, sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;
/* ── 색 · 종이(라이트) ── */
--surface: #fafaf8;
--surface-2: #f0f0ec;
--surface-3: #e5e5e0;
--line: #dcdcd6;
--line-strong: #b9b9b2;
--ink: #111214; /* 17.9:1 */
--ink-muted: #54585c; /* 6.97:1 */
--ink-faint: #686d72; /* 5.03:1 */
--accent: #c4341f; /* 5.21:1 · 흰 글자 얹으면 5.44:1 */
--accent-hover: #9e2817;
--accent-ink: #ffffff;
--accent-wash: #f6e7e3;
/* ── 색 · 잉크(다크 반전 밴드) — 위 값들의 규칙적 반전 ── */
--dark-surface: #111214;
--dark-surface-2: #191b1e;
--dark-surface-3: #212428;
--dark-line: #2c3034;
--dark-line-strong: #40454a;
--dark-ink: #f2f2f0; /* 16.7:1 */
--dark-ink-muted: #a2a6a9; /* 7.67:1 */
--dark-ink-faint: #84898d; /* 5.31:1 */
--dark-accent: #e8563c; /* 5.17:1 */
--dark-accent-hover: #f2705a;
--dark-accent-ink: #160906;
--dark-accent-wash: #33170f;
/* ── 형태 — 현행 사이트가 radius 0 으로 통일돼 있다. 유지할 자산이다 ── */
--radius: 0;
/* ── 간격 — 저장소 SSOT 표준 ── */
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 1rem;
--space-4: 1.5rem;
--space-5: 2.5rem;
--space-6: 4rem;
--space-7: 6rem;
--space-8: clamp(4.5rem, 3rem + 6vw, 9rem);
--container: 1120px;
--pad-inline: clamp(1.25rem, 1rem + 2.5vw, 4rem);
/* ── 모션 ── */
--dur-quick: 150ms;
--dur-normal: 380ms;
--ease: cubic-bezier(0.2, 0, 0, 1);
}