/* ---------- tokens ---------- */
:root{
  --bg:#ffffff;
  --ink:#16150f;
  /* 흰 바탕에서 3.4:1 이라 작은 글자 기준(4.5:1)에 미달이었다.
     .role · 화살표 · 모바일 설명이 이 값을 같이 쓴다 */
  --muted:#6b6558;
  --rule:#e6e2d8;

  --col:680px;
  --gap:104px;
}

/* ---------- reset ---------- */
*,*::before,*::after{box-sizing:border-box}
/* 스크롤바 자리를 항상 비워둔다. say hi 창을 열 때
   body 스크롤을 잠그는데, 그때 스크롤바가 사라지면 본문이
   그 폭만큼 오른쪽으로 밀렸다 돌아온다 (흔들림의 정체) */
html{-webkit-text-size-adjust:100%;scrollbar-gutter:stable}
body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",
              "Apple SD Gothic Neo","Malgun Gothic",sans-serif;
  font-size:15px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
img{display:block;max-width:100%;height:auto}
button{font:inherit;color:inherit;margin:0}

/* ---------- layout ---------- */
.wrap{
  width:min(92vw,var(--col));
  margin:0 auto;
  padding:clamp(72px,14vh,150px) 0 clamp(96px,20vh,200px);
}

/* ---------- intro ---------- */
.intro h1{
  font-size:24px;
  font-weight:600;
  letter-spacing:-.01em;
  margin:0 0 10px;
}
.tagline{
  margin:0 0 52px;
  font-size:13px;
  font-weight: 400;
  /* 굵기는 올리지 않는다 — 500 은 이름줄과 무게가 붙어버렸다.
     대신 색을 잉크에 가깝게 내려 선은 가는 채로 진하게만 한다 */
  color:#000;
}
.hi{margin:0;display:flex;align-items:center;gap:5px}
.sayhi{
  background:none;
  border:0;
  padding:0;
  font-size:15px;
  font-weight:500;
  text-decoration:underline;
  text-underline-offset:3px;
  text-decoration-thickness:1px;
  cursor:pointer;
}
.sayhi:hover{text-decoration-thickness:2px}

/* 손은 살짝 기울여 두고, say hi 위에 올리면 손목을 세운다.
   흔드는 대신 각도만 바꾼다 — 한 번 움직이고 그 자리에 머문다 */
.wave{
  display:inline-block;
  font-size:16px;
  line-height:1;
  transform:rotate(-14deg);
  transform-origin:50% 85%;   /* 손목 쪽을 축으로 */
  transition:transform .22s ease;
}
.hi:hover .wave,
.sayhi:focus-visible + .wave{
  transform:rotate(14deg);
}

/* ---------- works ---------- */
.works{
  margin-top:clamp(64px,11vh,120px);
  display:flex;
  flex-direction:column;
  gap:var(--gap);
}
/* 이미지 위에 레이어를 얹기 위한 기준.
   figcaption 은 이미지 밖이라 % 로는 못 얹는다. 이미지 비율이 1.33 고정이므로
   이미지 높이 = 100cqw / 1.33 = 75.19cqw 로 두고 cqw 로 좌표를 잡는다. */
.work{margin:0; position:relative; container-type:inline-size}

.shot{
  position:relative;
  display:block;
  overflow:hidden;
  border-radius:3px;
}
/* 링크 없는 항목은 커서·호버 반응 없음 */
div.shot{cursor:default}

.shot img{width:100%}

/* 화면 켜짐 오버레이 — JS 있을 때만 보인다.
   브라운관이 켜지는 순서를 그대로 따른다.
   ① 검은 화면  ② 가운데에 밝은 선이 그어짐  ③ 그 선이 위아래로 펼쳐지며 화면이 드러남
   검은 덮개를 위/아래 두 장으로 나눠 각각 바깥으로 걷어낸다. */
.screen{
  position:absolute;
  left:var(--l);
  top:var(--t);
  width:var(--w);
  height:var(--h);
  border-radius:2px;
  overflow:hidden;
  opacity:0;                 /* no-js 기본값: 아무것도 안 덮음 */
  pointer-events:none;
}
.js .screen{opacity:1}

/* 검은 덮개 위/아래 절반 */
.screen::before,
.screen::after{
  content:'';
  position:absolute;
  left:0;
  right:0;
  height:50.5%;
  background:#0b0b0d;
}
.screen::before{top:0;    transform-origin:center top}
.screen::after {bottom:0; transform-origin:center bottom}

/* 가운데 주사선 */
.beam{
  position:absolute;
  left:0;
  right:0;
  top:50%;
  height:2px;
  margin-top:-1px;
  background:#fffdf5;
  box-shadow:0 0 9px 1px rgba(255,253,240,.85);
  opacity:0;
  transform:scaleX(.12);
}

.js .shot.on .beam{
  animation:crt-beam 720ms ease-out forwards;
}
.js .shot.on .screen::before,
.js .shot.on .screen::after{
  animation:crt-open 460ms cubic-bezier(.34,.52,.24,1) 170ms forwards;
}

@keyframes crt-beam{
  0%  {opacity:0; transform:scaleX(.12)}
  14% {opacity:1; transform:scaleX(1)}
  55% {opacity:.8; transform:scaleX(1)}
  100%{opacity:0; transform:scaleX(1)}
}
@keyframes crt-open{
  from{transform:scaleY(1)}
  to  {transform:scaleY(0)}
}

/* ---------- caption ---------- */
figcaption{
  margin-top:18px;
  display:flex;
  flex-direction:column;
  gap:2px;
}
.name{
  font-size:15px;
  font-weight:500;
  letter-spacing:-.005em;
}
.arrow{
  display:inline-block;
  margin-left:5px;
  font-size:12px;
  color:var(--muted);
  transition:transform .18s ease,color .18s ease;
}
.role{
  /* 본문 Inter 를 그대로 받는다.
     이름줄과 같은 폰트가 됐으므로 굵기는 안 올린다 —
     올리면 두 줄이 한 덩어리로 보인다.
     자간도 뺀다. 모노스페이스라 벌려놓았던 값이다 */
  font-size:12.5px;
  color:var(--muted);
}

/* 링크 있는 항목만 호버 반응 */
a.shot + figcaption .name{text-decoration:underline transparent;text-underline-offset:3px;transition:text-decoration-color .18s ease}
.work:has(a.shot):hover .name{text-decoration-color:currentColor}
.work:has(a.shot):hover .arrow{transform:translate(2px,-2px);color:var(--ink)}
a.shot:focus-visible{outline:2px solid var(--ink);outline-offset:4px}



/* ---------- 호버 시 뜨는 설명 레이어 — 터미널 ----------
   목업 화면 안이므로 UI 다이얼로그가 아니라 "그 컴퓨터의 화면"처럼 보이게 한다.
   안쪽 문구는 전부 영문이라 IBM Plex Mono 하나로 충분하다. */
.info{
  position:absolute;
  left:var(--il); top:var(--it);
  width:var(--iw); height:var(--ih);
  z-index:2;
  overflow:hidden;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:9px;
  padding:14px 15px;
  border-radius:2px;
  background:#050a0c;
  color:#cfeff5;
  /* 고정폭을 여럿 대봤지만 다 안 맞았고, 결국 비고정폭인 이 서체로 정했다.
     터미널 느낌은 검은 판 · 주사선 · C:\> 프롬프트 줄이 만들고 있어서
     본문까지 고정폭일 필요가 없었다. 캡션의 IBM Plex Mono 와는 다른 서체다. */
  font-family:"Space Grotesk",ui-sans-serif,system-ui,sans-serif;
  /* 어두운 바탕의 밝은 글자는 실제보다 두껍고 빽빽해 보인다.
     자간을 조금 벌려야 답답하지 않다 */
  letter-spacing:.015em;
  opacity:0;
  transform:translateY(6px);
  transition:opacity .22s ease, transform .22s ease;
  pointer-events:none;   /* 숨길 때 display 를 쓰지 않는다 — 스크린리더에는 계속 읽히게 */
}
/* 주사선 — 화면 켜짐 효과와 같은 언어 */
.info::before{
  content:'';
  position:absolute; inset:0;
  pointer-events:none;
  background:repeating-linear-gradient(rgba(200,240,255,.05) 0 1px, transparent 1px 3px);
}
/* :focus-within 이 아니라 :focus-visible 이다.
   링크가 target=_blank 라 새 탭에서 돌아와도 <a> 에 포커스가 남는데,
   focus-within 이면 그동안 레이어가 계속 열려 있었다.
   focus-visible 은 마우스 클릭으로 생긴 포커스를 제외하고 키보드만 잡는다 */
.work:hover .info,
.work:has(:focus-visible) .info{opacity:1; transform:none}

/* 프롬프트 줄만 고정폭으로 남긴다 — 터미널 신호를 이 줄이 담당한다 */
.prompt{
  margin:0;
  font-family:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:12px;
  line-height:1.4;
  color:#5f8f96;
  letter-spacing:.02em;
}

/* 번짐(text-shadow)은 안 넣는다. 획이 뭉개져서 오히려 안 읽힌다.
   대신 굵기를 한 단계 올려 검은 바탕에서 가늘어 보이는 걸 막는다 */
.desc{
  margin:0;
  font-size:12.5px;
  font-weight:500;
  line-height:1.65;
}
/* 타이핑 애니메이션과 깜빡이는 커서는 뺐다.
   한 화면에 항목이 여럿이라 호버할 때마다 글자가 다시 찍히는 게 산만했다.
   레이어는 그냥 조용히 떠 있고, 움직이는 건 화면 켜짐 효과 하나뿐이다. */

/* 태그는 네모 상자를 두르지 않는다. 상자가 있으면 검은 화면 안에서
   요즘 UI 칩처럼 보였다. 가운뎃점으로 나눈 한 줄이면 충분하다.
   색만 본문과 다르게(노랑) 줘서 설명과 구분한다 */
.tags{
  margin:0; padding:0; list-style:none;
  display:flex; flex-wrap:wrap; gap:0;
}
.tags li{
  font-size:11px;
  font-weight:500;
  line-height:1.3;
  color:#ffd98a;
}
.tags li + li::before{content:'\00b7'; margin:0 7px; opacity:.55}

/* 폰(wez)은 화면 폭이 랩탑의 60% 뿐이라 한 단계 줄인다.
   또 랩탑과 달리 화면 주변에 두꺼운 검은 베젤이 있다. 패널 배경은 베젤까지
   덮어야 경계가 안 보이지만(둘 다 검정), 글자는 실제로 켜진 영역 안에 있어야 한다.
   그래서 안쪽 여백을 베젤 두께만큼 준다 — 위가 두꺼운 건 상태표시줄 자리다. */
.work--narrow .info{padding:5.45cqw 3.53cqw 2.46cqw 4.17cqw; gap:7px}
.work--narrow .prompt{font-size:11px}
.work--narrow .desc{font-size:11.5px; line-height:1.6}
.work--narrow .tags li{font-size:10px}

/* ---------- 모바일 ----------
   데스크탑의 터미널 레이어를 그대로 축소하지 않는다. 화면이 너무 좁아서
   목업 위에 어두운 판을 덮으면 작업물도 안 보이고 글도 안 읽힌다.
   모바일에서는 캡션 오른쪽 끝의 작은 텍스트 버튼으로 열고,
   설명은 이미지 아래에 사이트 본문과 같은 타이포로 펼친다. */
.infobtn{display:none}

@media (hover:none), (max-width:760px){
  /* 이름은 한 줄 전체, 역할과 버튼은 같은 줄 양끝, 설명은 그 아래 */
  figcaption{
    display:grid;
    grid-template-columns:1fr auto;
    align-items:baseline;
    gap:2px 14px;
  }
  .name{grid-column:1 / -1; grid-row:1}
  .role{grid-column:1; grid-row:2}
  .infobtn{grid-column:2; grid-row:2; justify-self:end}
  .info{grid-column:1 / -1; grid-row:3}

  /* 아이콘은 ↗ 화살표와 같은 언어로 — 채우지 않고 가는 선으로만 그린다.
     보이는 크기는 16px, 손가락이 닿는 영역은 여백으로 32px 로 넓힌다.
     여백만큼 바깥으로 당겨서 줄맞춤은 그대로 둔다. */
  .infobtn{
    display:inline-flex; align-self:center;
    padding:8px; margin:-8px -8px -8px 0;
    border:0; background:none;
    color:var(--muted);
    cursor:pointer;
    -webkit-tap-highlight-color:transparent;
    transition:color .18s ease;
  }
  .infobtn .ic{
    width:16px; height:16px; display:block;
    fill:none; stroke:currentColor; stroke-width:1.1;
    stroke-linecap:round;
  }
  .infobtn .ic-i path:last-child{stroke-width:1.6}   /* i 의 점 */
  .infobtn .ic-x{display:none}
  .work.info-open .infobtn{color:var(--ink)}
  .work.info-open .infobtn .ic-i{display:none}
  .work.info-open .infobtn .ic-x{display:block}

  /* 접혔을 때는 자리를 차지하지 않아야 한다. aria-expanded 가 상태를 알려주므로
     여기서는 display 로 접는 게 맞다 */
  .info{
    display:none;
    position:static;
    width:auto; height:auto;
    padding:13px 0 2px; margin-top:9px;
    border-top:1px solid var(--rule);
    border-radius:0;
    background:none;
    color:var(--ink);
    font-family:"Inter",system-ui,sans-serif;
    opacity:1; transform:none;
    pointer-events:auto;
  }
  /* .work--narrow .info 는 선택자가 더 구체적이라 위 규칙을 이기고 안쪽 여백을
     그대로 밀고 들어온다. 같은 구체성으로 되돌린다 */
  .work--narrow .info{padding:13px 0 2px; gap:0}
  .info::before{content:none}          /* 주사선 없음 */
  .work.info-open .info{display:block; animation:info-in .2s ease}
  @keyframes info-in{from{opacity:0} to{opacity:1}}

  .prompt{display:none}                /* C:\\> 는 데스크탑 터미널 전용 */

  /* 데스크탑에서 준 굵기 500 과 벌린 자간은 검은 화면 위에서만 필요한 보정이다.
     모바일은 흰 바탕에 사이트 본문 타이포를 그대로 쓰므로 되돌린다 */
  .desc,
  .work--narrow .desc{
    font-size:13px;
    font-weight:400;
    line-height:1.75;
    letter-spacing:-.005em;
    color:var(--ink);
    font-family:inherit;
  }

  /* 태그도 상자를 두르지 않는다. 가운뎃점으로 나눈 한 줄 */
  .tags{margin-top:8px; gap:0}
  .tags li,
  .work--narrow .tags li{
    padding:0; border:0;
    color:var(--muted);
    font-family:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
    font-size:11.5px; font-weight:400; line-height:1.6; letter-spacing:.02em;
  }
  .tags li + li::before{content:'·'; margin:0 7px; color:var(--rule)}

  /* 호버로는 열리지 않는다 */
  .work:hover .info,
  .work:has(:focus-visible) .info{display:none}
  .work.info-open .info{display:block}
}

/* ---------- say hi 팝업창 ----------
   예날 창의 구조를 그대로 쓴다. 제목 왼쪽 · 닫기 오른쪽 ·
   각진 모서리 · 2겹 테두리로 만든 입체감.
   튀어나옴: 바깥 밝음/어둠, 안쪽 흰색/그늘
   들어감  : 반대로

   색만 Win95 기본값에서 바꿨다. 본체를 #c0c0c0 대신 훨씬 밝은
   #e9e9e9 로 올려서 답답함을 뺀 다음, 제목표시줄에만 남색을 남겼다.
   그리고 --w-dark 는 테두리의 그늘 색이라 글자에 쓰면 흐려진다.
   글자색은 --w-ink 로 따로 둔다. */
:root{
  --w-face:#e9e9e9;
  --w-hi:#ffffff;
  --w-light:#f5f5f5;
  --w-shadow:#bcbcbc;
  --w-dark:#8a8a8a;
  --w-title:#000080;
  --w-ink:#2f2f2f;
}

.overlay{
  position:fixed;
  inset:0;
  display:none;
  /* 창이 화면보다 길어지면(키보드가 올라온 폰) 안에서 스크롤돼야 한다.
     align-items:center 는 넘칠 때 위쪽을 잘라버리므로 쓰지 않고,
     창 쪽에 margin:auto 를 준다 — 넘치지 않으면 가운데, 넘치면 스크롤 */
  overflow-y:auto;
  -webkit-overflow-scrolling:touch;
  padding:20px;
  background:rgba(0,0,0,.35);
  z-index:50;
}
.overlay.open{display:flex}

.window{
  /* 가운데 정렬. flex 아이템의 margin:auto 는 넘칠 때도 위를 안 자른다 */
  margin:auto;
  /* 폭만 넓힌다. 글자 크기·여백·제목줄 높이는 서로 물려 있는 체계라 안 건드린다.
     창 폭은 그 체계 밖이라 혼자 바꿔도 비율이 안 깨진다. */
  width:min(100%,450px);
  background:var(--w-face);
  color:var(--w-ink);
  padding:3px;
  border:1px solid;
  border-color:var(--w-light) var(--w-dark) var(--w-dark) var(--w-light);
  box-shadow:
    inset 1px 1px 0 var(--w-hi),
    inset -1px -1px 0 var(--w-shadow),
    3px 3px 0 rgba(0,0,0,.28);
  font-family:Tahoma,"MS Sans Serif",Geneva,Verdana,sans-serif;
  font-size:12px;
  /* 끌어서 올긴 거리. 가운데 정렬은 overlay 가 하고
     이 값은 거기서부터의 어긋나금이라 둘이 안 싸운다 */
  transform:translate(var(--dx,0px),var(--dy,0px));
}

.titlebar{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:10px;
  height:20px;
  padding:0 2px 0 4px;
  background:var(--w-title);
  color:#fff;
  /* 제목줄은 잡아끄는 자리다 */
  cursor:move;
  user-select:none;
  -webkit-user-select:none;
  touch-action:none;
}
/* 터치 기기에서는 끌기를 아예 없앤다. touch-action:none 을 남겨두면
   제목줄에서 시작한 스크롤이 먹히지 않는다 */
@media (hover:none){
  .titlebar{cursor:default; touch-action:auto}
}
/* 닫기 버튼은 끌기는 게 아니라 누르는 것 */
.titlebar .close{cursor:pointer}
.title{
  display:inline-flex;
  align-items:center;
  gap:5px;
  font-size:12px;
  font-weight:700;
  letter-spacing:0;
}
/* 스마일은 16x16 격자에 칸을 찍어서 만든 비트맵이다.
   제목줄 색을 따라가지 않고 항상 노랑으로 둔다 */
.title-icon{width:16px;height:16px;flex:none;display:block}

.close{
  width:17px;height:15px;
  display:grid;place-items:center;
  padding:0 0 1px;
  font-family:inherit;
  font-size:11px;
  font-weight:700;
  line-height:1;
  background:var(--w-face);
  color:var(--w-ink);
  border:1px solid;
  border-color:var(--w-light) var(--w-dark) var(--w-dark) var(--w-light);
  box-shadow:inset 1px 1px 0 var(--w-hi),inset -1px -1px 0 var(--w-shadow);
  cursor:pointer;
}
.close:active{
  border-color:var(--w-dark) var(--w-light) var(--w-light) var(--w-dark);
  box-shadow:inset 1px 1px 0 var(--w-shadow),inset -1px -1px 0 var(--w-hi);
}

.window-body{padding:14px 12px 12px}
.window-body label{
  display:block;
  font-size:12px;
  margin:0 0 3px;
  color:var(--w-ink);
}
.window-body input,
.window-body textarea{
  width:100%;
  font-family:inherit;
  font-size:12px;
  color:#1c1c1c;
  background:#fff;
  border:1px solid;
  border-color:var(--w-shadow) var(--w-hi) var(--w-hi) var(--w-shadow);
  box-shadow:inset 1px 1px 0 var(--w-dark),inset -1px -1px 0 var(--w-light);
  border-radius:0;
  padding:4px 5px;
  margin:0 0 11px;
  resize:vertical;
}
/* 메시지 칸은 높이만 키운다. 높이는 글자크기·여백 체계와
   묶여 있지 않아서 이것만 건드려도 비율이 안 깨진다 */
.window-body textarea{min-height:160px}
/* 칸 길이를 내용에 맞춘다. 옛날 대화상자는 입력칸을 창 끝까지 늘이지 않고
   들어갈 내용만큼만 잘랐다. 이름 몇 글자 쓰는 칸이 450px 이면 어색하다.
   좁은 화면에서는 고정폭이 창 밖으로 삐져나오므로 100% 를 넘지 않게 묶는다. */
#f-name{width:min(200px,100%)}
#f-email{width:min(270px,100%)}
/* iOS 는 글자가 16px 보다 작은 입력칸을 누르면 화면을 확대해 버린다.
   확대되면 창이 화면 밖으로 밀려나므로 터치 기기에서만 16px 로 올린다.
   데스크탑 창은 12px 그대로다 */
@media (hover:none){
  .window-body input,
  .window-body textarea{font-size:16px}
}
.window-body input:focus,
.window-body textarea:focus{outline:1px dotted #000;outline-offset:-3px}

.actions{display:flex;align-items:center;justify-content:space-between;gap:12px}
.status{margin:0;font-size:11px;line-height:1.35;color:var(--w-ink);min-height:1.35em}

.btn{
  min-width:82px;
  padding:5px 14px 6px;
  font-family:inherit;
  font-size:12px;
  background:var(--w-face);
  color:var(--w-ink);
  border:1px solid;
  border-color:var(--w-light) var(--w-dark) var(--w-dark) var(--w-light);
  box-shadow:inset 1px 1px 0 var(--w-hi),inset -1px -1px 0 var(--w-shadow);
  cursor:pointer;
}
.btn:active{
  border-color:var(--w-dark) var(--w-light) var(--w-light) var(--w-dark);
  box-shadow:inset 1px 1px 0 var(--w-shadow),inset -1px -1px 0 var(--w-hi);
  padding:6px 13px 5px 15px;
}
.btn[disabled]{color:#9a9a9a;cursor:default}

/* ---------- responsive ---------- */
@media (max-width:600px){
  :root{--gap:72px}
  .wrap{width:88vw}
  .intro h1{font-size:19px}
}

/* 화면 켜짐 효과는 OS의 "애니메이션 끄기" 설정과 무관하게 항상 재생한다 */

/* 봇 함정 칸. display:none 은 일부 봇이 알아채므로 화면 밖으로 치운다 */
.hp{
  position:absolute;
  left:-9999px;
  width:1px; height:1px;
  overflow:hidden;
}
