@charset "utf-8";
/* ==========================================================================
   base.css — 공통 토큰 · 리셋 · 기본 타이포 · 접근성 유틸
   --------------------------------------------------------------------------
   프로젝트 : 웹퍼블리셔 포트폴리오 (그누보드5 커스텀 테마)
   로드 순서: base.css → layout.css → (페이지별 CSS)
   원칙     : 순수 CSS · 모바일 우선 · 값은 전부 아래 :root 토큰에서만 가져다 씀

   ※ 이 파일에는 "화면에 보이는 컴포넌트"를 만들지 않는다.
     여기서 정의한 토큰을 다른 파일이 소비하는 단방향 구조를 유지해야
     색·간격을 한 곳에서 바꿀 수 있다. (확장성 / 일관성)
   ========================================================================== */


/* ==========================================================================
   1. 디자인 토큰
   ========================================================================== */

:root {

  /* ---- 1-1. 컬러 : 원색 팔레트 --------------------------------------------
     역할이 아니라 "색 그 자체"의 이름. 컴포넌트에서 직접 쓰지 말고,
     아래 1-2 시맨틱 토큰을 통해서만 사용한다.
     (색을 바꿀 때 여기만 고치면 되도록 2단 구조로 분리)
  ------------------------------------------------------------------------ */

  /* 메인 — 버건디 */
  --c-burgundy:        #8B2635;
  --c-burgundy-dark:   #6E1D2A;   /* hover / active 용 (시안에서 실사용) */

  /* 서브 — 딥 그린 */
  --c-green:           #3F5B52;

  /* 뉴트럴 — 웜 계열 (오프화이트 → 잉크) */
  --c-paper:           #F7F4EF;   /* 페이지 배경 */
  --c-paper-raised:    #FFFDF9;   /* 카드 등 배경 위로 떠 있는 면 */
  --c-paper-sunken:    #EFEAE2;   /* 배경보다 한 톤 눌린 구역 */
  --c-line:            #DCD5CB;   /* 구분선 · 격자 배경선 */
  --c-line-strong:     #C9C2B7;   /* 강조 테두리 */
  --c-gray:            #A29A93;   /* 비활성 · 3차 텍스트 */
  --c-gray-dark:       #6B645E;   /* 보조 텍스트 */
  --c-gray-deep:       #55504B;   /* 배경이 흐린 곳(인트로 위 헤더)에서 쓰는 보조 텍스트 */
  --c-stripe:          #E2DCD2;   /* 썸네일 자리표시 줄무늬 (시안 값) */
  --c-matte:           #FFFFFF;   /* 썸네일 여백 매트 — --color-thumb-matte 설명 참고 */
  --c-ink-soft:        #3A3134;   /* 반전 섹션 위의 카드 면 */
  --c-ink:             #1C1417;   /* 반전 섹션 배경 */
  --c-text:            #1C1917;   /* 본문 텍스트 */

  /* 상태색 — 게시판 폼 검증 등에서만 사용 (강조색과 섞지 않는다) */
  --c-error:           #B3261E;
  --c-success:         #3F5B52;


  /* ---- 1-2. 컬러 : 시맨틱 토큰 -------------------------------------------
     컴포넌트는 무조건 이 이름으로만 색을 참조한다.
     "--color-accent 를 쓴다"고 쓰면 나중에 강조색이 바뀌어도 코드는 그대로다.

     ※ CLAUDE.md 규칙: 강조색은 화면당 한 곳에 집중.
       버건디(accent)와 딥 그린(accent-alt)을 같은 영역에 나란히 쓰지 않는다.
  ------------------------------------------------------------------------ */

  --color-bg:              var(--c-paper);
  --color-bg-raised:       var(--c-paper-raised);
  --color-bg-sunken:       var(--c-paper-sunken);

  --color-text:            var(--c-text);
  --color-text-sub:        var(--c-gray-dark);   /* 종이색 위 5.2:1 — 본문 사용 가능 */
  --color-text-sub-deep:   var(--c-gray-deep);   /* 인트로 그라디언트 위 5.6:1 — 헤더용 */
  --color-text-muted:      var(--c-gray);        /* 대비 2.6:1 — 큰 글씨/장식 전용 */

  --color-border:          var(--c-line);
  --color-border-strong:   var(--c-line-strong);

  /* 썸네일 여백 매트.
     그누보드는 썸네일을 자르지 않고 만들 때(is_crop=false) 원본 비율을 유지한 채
     축소한 뒤 남는 자리를 흰색으로 채운 파일을 저장한다. 그 여백은 이미지 파일에
     이미 구워져 있어 CSS로는 바꿀 수 없으므로, 썸네일을 담는 상자의 배경을 같은
     흰색으로 맞춰 경계가 드러나지 않게 한다.
     오프화이트(--c-paper-raised)를 쓰면 두 흰색의 차이가 띠로 보인다. */
  --color-thumb-matte:     var(--c-matte);

  --color-accent:          var(--c-burgundy);      /* 주요 강조 · 링크 · 버튼 */
  --color-accent-hover:    var(--c-burgundy-dark);
  --color-accent-alt:      var(--c-green);         /* 태그 칩 · 보조 강조 */

  /* 색 반전(잉크) 섹션에서 위 토큰을 덮어쓸 때 사용 → 3-4 .is-inverted 참고 */
  --color-bg-invert:       var(--c-ink);
  --color-bg-invert-raised:var(--c-ink-soft);
  --color-text-invert:     var(--c-paper);

  /* 포커스 링 — 접근성상 절대 색을 흐리게 만들지 않는다 */
  --color-focus:           var(--c-burgundy);

  /* 반투명 파생값. color-mix() 대신 rgba를 쓰는 이유는 구형 브라우저 대응
     (크로스 브라우징 우선 원칙). 값이 필요하면 여기에 추가한다. */
  --color-overlay:         rgba(28, 20, 23, 0.55);
  --color-shadow:          rgba(28, 20, 23, 0.14);


  /* ---- 1-3. 타이포 : 폰트 패밀리 ----------------------------------------- */

  /* 본문 — Pretendard. 로컬 설치본 → 웹폰트 → 시스템 폰트 순으로 폴백.
     'Pretendard Variable'을 먼저 두어 가변 폰트가 있으면 그걸 쓴다. */
  --font-sans:
    'Pretendard Variable', Pretendard,
    -apple-system, BlinkMacSystemFont,
    'Apple SD Gothic Neo', 'Malgun Gothic', '맑은 고딕',
    system-ui, sans-serif;

  /* 소형 라벨 · 메타 정보 전용 모노스페이스 */
  --font-mono:
    'IBM Plex Mono', 'D2Coding', ui-monospace,
    SFMono-Regular, Consolas, 'Courier New', monospace;


  /* ---- 1-4. 타이포 : 크기 -------------------------------------------------
     고정 크기는 rem(사용자 브라우저 글꼴 설정 존중 → 접근성),
     큰 문장은 clamp(최소, 기준+뷰포트비례, 최대)로 화면 폭에 따라 무단계 확대.

     clamp의 중간값을 "rem + vw" 형태로 쓰는 이유:
     100% vw로만 하면 사용자가 브라우저 글꼴을 키워도 글자가 안 커져
     WCAG 1.4.4(200% 확대) 위반이 된다. rem을 섞어야 확대가 먹는다.
  ------------------------------------------------------------------------ */

  /*
   * 최대값은 전부 시안의 1440px 실측값이다. 임의로 키우지 않는다.
   * 중간항(rem + vw)은 "390px에서 시안 모바일 값 → 1440px에서 시안 데스크톱 값"이
   * 되도록 역산했다. 계산법:
   *   기울기(vw) = (데스크톱값 - 모바일값) / (1440 - 390) * 100
   *   절편(rem)  = 모바일값 - 기울기 * 390
   * rem 절편을 남겨 두는 이유는 사용자가 브라우저 기본 글꼴을 키웠을 때도
   * 글자가 따라 커지게 하기 위해서다(vw 만 쓰면 확대가 먹지 않는다).
   */
  --fs-wordmark:  clamp(4rem,     0.5rem   + 17.5vw, 11rem   ); /*    → 176 푸터 워드마크 */
  --fs-display:   clamp(2.5rem,   1.664rem +  3.43vw, 4.75rem); /* 40 →  76 인트로 h1 */
  --fs-h1:        clamp(2rem,     1.25rem  +  3.7vw,  3.625rem); /* 32 →  58 게시판 페이지 제목 */
  --fs-h2:        clamp(1.625rem, 1.16rem  +  1.9vw,  2.875rem); /* 26 →  46 섹션 제목 */
  --fs-h2-about:  clamp(1.75rem,  1.193rem +  2.29vw, 3.25rem ); /* 28 →  52 소개 섹션 제목 */
  --fs-h3-feature:clamp(1.75rem,  1.518rem +  0.95vw, 2.375rem); /* 28 →  38 대표작 카드 제목 */
  --fs-h3:        clamp(1.5rem,   1.454rem +  0.19vw, 1.625rem); /* 24 →  26 일반 카드 제목 */
  --fs-h4:                                            1.125rem;  /*        18 */

  --fs-lead:     clamp(1.0625rem, 1rem + 0.5vw,     1.3125rem); /* 17 → 21 본문 리드 */
  --fs-body:                                        1rem;      /* 16 기본 본문 */
  --fs-sm:                                          0.9375rem; /* 15 보조 본문 */
  --fs-xs:                                          0.8125rem; /* 13 캡션 */

  --fs-label:                                       0.75rem;   /* 12 모노 라벨 */
  --fs-label-sm:                                    0.6875rem; /* 11 모노 소형 라벨 */
  --fs-label-xs:                                    0.625rem;  /* 10 모노 최소 라벨 (칩·통계 항목명) */


  /* ---- 1-5. 타이포 : 굵기 · 행간 · 자간 -----------------------------------
     CLAUDE.md 규칙: 큰 문장은 굵기를 낮추고 크기를 키운다.
     그래서 display/h1에는 --fw-regular~medium 을 쓰고 bold를 쓰지 않는다.
  ------------------------------------------------------------------------ */

  --fw-regular:  400;
  --fw-medium:   500;
  --fw-semibold: 600;

  --lh-tight:    1.08;   /* 대형 타이포 — 크면 클수록 행간을 좁힌다 */
  --lh-heading:  1.28;
  --lh-base:     1.7;    /* 한글 본문 가독성 기준 */
  --lh-relaxed:  1.85;

  /* 한글은 자간을 살짝 조여야 덜 벌어져 보인다(음수). 모노 라벨은 반대로 넓힌다. */
  --ls-display: -0.03em;
  --ls-heading: -0.02em;
  --ls-base:    -0.01em;
  --ls-label:    0.16em;
  --ls-label-lg: 0.18em;


  /* ---- 1-6. 간격 스케일 ---------------------------------------------------
     4px 배수 고정. 임의 값(예: 13px, 27px)을 쓰지 않기 위한 장치다.
     "간격이 애매하다" 싶으면 값을 새로 만들지 말고 인접 단계를 고른다.
  ------------------------------------------------------------------------ */

  --sp-1:  0.25rem;  /*  4 */
  --sp-2:  0.5rem;   /*  8 */
  --sp-3:  0.75rem;  /* 12 */
  --sp-4:  1rem;     /* 16 */
  --sp-5:  1.5rem;   /* 24 */
  --sp-6:  2rem;     /* 32 */
  --sp-7:  2.5rem;   /* 40 */
  --sp-8:  3.5rem;   /* 56 */
  --sp-9:  5rem;     /* 80 */
  --sp-10: 7.5rem;   /* 120 */

  /* 섹션 상하 여백 — 모바일에선 좁게, 데스크톱에선 넓게 자동 전환 (88px → 176px)
     대형 타이포를 쓰는 레이아웃은 여백이 좁으면 글자 덩어리끼리 붙어 보여
     섹션 경계가 구분선에만 의존하게 된다. 여백 자체가 구분 역할을 하도록 키운 값. */
  --sp-section: clamp(5.5rem, 3rem + 8vw, 11rem);


  /* ---- 1-7. 레이아웃 ------------------------------------------------------ */

  /*
   * 헤더는 문서 흐름에서 빠져(fixed) 본문 위에 겹쳐 뜬다.
   * 그래서 본문이 헤더 밑에 깔리지 않도록 이 높이만큼 여백을 직접 확보해야 한다.
   *
   * 여기 값은 JS(ui.js)가 실제 측정값으로 덮어쓰기 전까지 쓰이는 폴백이다.
   * 74px = 헤더 위쪽 패딩 12 + 바 62(--bar-h).
   *
   * ※ 손으로 계산한 값을 최종 근거로 삼지 않는다. 이전에 72px 로 적어 뒀다가
   *   실제 높이가 80px 이라 앵커 이동 때 섹션이 헤더에 8px 가려졌다.
   *   폰트 로드·사이트명 길이·글꼴 설정에 따라 달라지므로 ui.js 가 실측해 갱신한다.
   */
  --header-h: 4.625rem;

  /* 앵커로 이동했을 때 목적지 내용이 서야 할 화면상 위치.
     헤더가 가리는 높이 + 숨 쉴 여유. 스크롤 관련 값은 전부 이 토큰을 쓴다. */
  --anchor-offset: calc(var(--header-h) + var(--sp-4));

  /* 맨 위로 버튼. 44px 은 임의로 고른 값이 아니라 최소 터치 타깃 기준
     (WCAG 2.5.5 Target Size)에서 가져왔다. 그보다 작으면 모바일에서 헛누른다.
     clearance = 버튼이 화면 아래쪽에서 차지하는 총 높이(버튼 + 아래 여백).
     푸터가 이 값만큼 아래 여백을 더 잡아, 버튼이 저작권 줄을 덮지 않게 한다. */
  --to-top-size: 2.75rem;   /* 44 */
  --to-top-clearance: calc(var(--to-top-size) + var(--gutter));

  /* 반투명 유리 표면 — 상태에 따라 두 단계를 쓴다.
     캡슐은 높이 48px 짜리 얇은 띠라 뒤가 많이 비쳐도 글자를 읽는 데 지장이 없다.
     반면 펼쳐진 드롭다운은 면적이 넓어 뒤 콘텐츠가 그대로 비치면 글자와 겹친다.
     그래서 닫힌 상태는 비침을 살리고, 열린 상태에서만 불투명도를 끌어올린다.
     (열릴 때는 캡슐도 아래 값으로 함께 바뀌어야 두 요소가 한 덩어리로 보인다) */
  --surface-glass:       rgba(255, 253, 249, 0.58);  /* 닫힌 캡슐 — 잘 비침 */
  --surface-glass-solid: rgba(255, 253, 249, 0.94);  /* 열린 캡슐 + 드롭다운 — 가독성 */

  /* 블러는 비침을 유지한 채 뒤 배경의 '형태'만 뭉갠다.
     가독성이 부족할 때 불투명도보다 이쪽을 먼저 올리는 편이 손해가 적다. */
  --surface-blur:        blur(12px) saturate(1.4);
  --surface-blur-strong: blur(22px) saturate(1.5);

  --container-max:  78.75rem;                    /* 1260px — 콘텐츠 최대 폭 */
  --container-wide: 90rem;                       /* 1440px — 풀블리드 상한 */
  --gutter: clamp(1.25rem, 0.5rem + 3.5vw, 4rem);/* 좌우 안전 여백 20 → 64 */

  --grid-cols: 4;    /* 모바일 기본 컬럼 수. 3장 미디어쿼리에서 8 → 12로 증가 */
  --grid-gap:  clamp(1rem, 0.5rem + 1.6vw, 1.75rem);

  /* 격자 배경선(레퍼런스: Chemistry) 두께 — 1px 고정, 색은 --color-border */
  --grid-line-w: 1px;


  /* ---- 1-8. 모서리 · 그림자 ---------------------------------------------- */

  /*
   * 각진 모서리가 이 디자인의 정체성이다.
   * 둥근 모서리는 네비게이션 바 하나에만 허용하고, 그 값은 헤더 안에서
   * --bar-radius 로 따로 관리한다(layout.css). 여기 토큰이 0 이므로
   * 카드·칩·버튼은 어디서 var(--radius-*) 를 참조하든 각지게 나온다.
   */
  --radius-sm:   0;
  --radius-md:   0;
  --radius-lg:   0;
  --radius-pill: 999px;   /* 햄버거 버튼(원형)에만 사용 */

  --shadow-sm: 0 1px 2px var(--color-shadow);
  --shadow-md: 0 8px 24px -12px var(--color-shadow);
  --shadow-lg: 0 24px 60px -30px rgba(28, 20, 23, 0.35);
  --shadow-card: 0 22px 44px -30px rgba(28, 20, 23, 0.5);   /* 카드 hover (시안 값) */


  /* ---- 1-9. 모션 ----------------------------------------------------------
     duration/easing을 토큰화해야 네비 수축·드롭다운·호버의 리듬이 일치한다.
     --ease-out 은 처음 빠르고 끝에서 부드럽게 멈추는 곡선(시안과 동일 값).
  ------------------------------------------------------------------------ */

  --dur-fast: 160ms;
  --dur-base: 280ms;
  --dur-slow: 550ms;

  --ease-out:   cubic-bezier(0.32, 0.72, 0, 1);
  --ease-inout: cubic-bezier(0.65, 0, 0.35, 1);


  /* ---- 1-10. z-index ------------------------------------------------------
     숫자를 코드 곳곳에 흩뿌리면 "9999 전쟁"이 난다. 층을 여기서 한 번에 관리.
  ------------------------------------------------------------------------ */

  --z-base:     1;
  --z-sticky:   40;   /* 상단 네비 */
  --z-dropdown: 50;   /* 햄버거 드롭다운 */
  --z-overlay:  60;   /* 배경 딤 */
  --z-skip:     70;   /* 스킵 네비 — 항상 최상단 */
}


/* ==========================================================================
   2. 리셋 · 노멀라이즈
   필요한 것만 최소로. (그누보드 기본 CSS가 함께 로드될 수 있어
   과도한 전역 초기화는 게시판 화면을 깨뜨린다 — 안정성 우선)
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  /* font-size를 %/px로 덮어쓰지 않는다.
     사용자가 브라우저에서 키운 글꼴 크기를 그대로 존중해야 rem이 의미를 갖는다. */
  -webkit-text-size-adjust: 100%;   /* iOS 가로 회전 시 글자 자동 확대 방지 */
  text-size-adjust: 100%;
  scroll-behavior: smooth;

  /* 앵커로 이동했을 때 고정 헤더가 제목을 덮지 않도록 그만큼 미리 띄운다.
     scroll-padding 은 "스크롤 컨테이너"에 붙이는 속성이다 — 여기서는 문서 뷰포트.
     다만 새 페이지를 열면서 주소 끝에 #앵커가 붙은 경우(초기 로드 프래그먼트)에는
     적용이 보장되지 않는다. 그래서 아래 [id] 규칙으로 목적지 쪽에도 여백을 준다. */
  scroll-padding-top: var(--anchor-offset);
}

body {
  margin: 0;
  background-color: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-base);
  letter-spacing: var(--ls-base);
  word-break: keep-all;   /* 한글이 단어 중간에서 끊기지 않게 */
  overflow-wrap: break-word;  /* 단, 긴 URL 등은 강제 줄바꿈 허용 */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/*
 * 앵커 목적지 여백.
 *
 * scroll-margin-top 은 "목적지 요소"에 붙이는 속성이라, 스크롤을 누가 어떻게
 * 일으켰든(링크 클릭, 새 페이지 로드 시 #앵커, JS의 scrollIntoView) 항상 적용된다.
 * 위 html 의 scroll-padding-top 과 목적은 같지만 붙는 위치가 반대다.
 *
 * id 가 있는 모든 요소에 거는 이유: 게시판 스킨이 만들어 내는 앵커(#bo_v 등)까지
 * 한 번에 덮기 위해서다. 스크롤이 그 요소에서 멈출 때만 관여하므로
 * 평소 레이아웃에는 아무 영향이 없다.
 */
[id] {
  scroll-margin-top: var(--anchor-offset);
}

/* 여백은 컴포넌트가 정한다. 기본 마진 제거 후 필요한 곳에서만 부여. */
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd {
  margin: 0;
}

ul, ol {
  margin: 0;
  padding: 0;
}

/* 목록 마커 제거는 내비게이션 등 UI 목록에 한정.
   본문 안 목록은 .prose 같은 콘텐츠 스코프에서 되살린다. */
nav ul,
nav ol {
  list-style: none;
}

/* 큰 문장 규칙: 크기를 키우고 굵기는 낮춘다 */
h1, h2, h3, h4, h5, h6 {
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-heading);
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }
h4 { font-size: var(--fs-h4); }

a {
  color: var(--color-accent);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out);
}

/* 밑줄을 hover에서 되살리는 이유: 링크임을 색만으로 알리면
   색각 이상 사용자에게 구분이 안 된다(WCAG 1.4.1 색에만 의존 금지).
   본문 링크는 컴포넌트 CSS에서 항상 밑줄을 유지시킨다. */
a:hover {
  color: var(--color-accent-hover);
  text-decoration: underline;
  text-underline-offset: 3px;
}

img,
picture,
svg,
video {
  display: block;      /* inline 기본값 때문에 생기는 아래쪽 4px 여백 제거 */
  max-width: 100%;
  height: auto;
}

/* 폼 요소는 폰트를 상속하지 않으므로 명시적으로 물려준다 */
button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}

button {
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

textarea {
  resize: vertical;
}

/*
 * fieldset · legend 는 브라우저 기본 스타일이 유난히 강하다.
 *   border: 2px groove   → 요청하지 않은 회색 홈 테두리
 *   margin: 0 2px        → 좌우로 2px 씩 어긋남
 *   min-width: min-content → 그리드·플렉스 칸 안에서 줄어들지 않아 넘침
 * 셋 다 지우고, 필요한 테두리는 각 컴포넌트가 직접 그린다.
 * (게시판 쓰기 화면의 .pf-fieldset, 캡차 플러그인의 #captcha 가 모두 여기 걸린다)
 */
fieldset {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

legend {
  padding: 0;
}

table {
  width: 100%;
  border-collapse: collapse;
}

hr {
  height: 0;
  margin: 0;
  border: 0;
  border-top: 1px solid var(--color-border);
}

address {
  font-style: normal;
}


/* ---- 2-1. 스크롤바 ----------------------------------------------------------
   브라우저마다 방식이 둘이고, 둘 다 쓴다. 이유는 지원 범위가 서로 엇갈려서다.

     표준 속성(scrollbar-width · scrollbar-color)
       Firefox 64+, Chrome/Edge 121+, Safari 18.2+ 지원.
       두께는 auto|thin|none 세 단계뿐이고 모서리·트랙 테두리는 못 건드린다.
     ::-webkit-scrollbar 계열
       WebKit/Blink 전용 비표준. 두께·모서리·트랙을 픽셀 단위로 그릴 수 있다.

   둘이 겹치는 브라우저(Chrome 121+)에서는 표준 속성이 이기고 ::-webkit-scrollbar
   규칙은 무시된다. 그래서 아래 두 블록은 경쟁이 아니라 분담이다.
     - 표준을 아는 브라우저 → 표준 (얇게 + 사이트 색)
     - 모르는 브라우저(구형 Chrome·Safari) → webkit (얇게 + 사이트 색 + 각진 썸 + 트랙 실선)
     - 둘 다 모르는 브라우저 → 손대지 않은 기본 스크롤바. 기능은 그대로다.

   색은 강조색(버건디)을 쓰지 않는다. 스크롤바는 모든 페이지에 항상 떠 있어서,
   여기에 강조색을 쓰면 "화면당 한 곳" 규칙이 매 화면에서 깨진다.
   잉크-그레이 계열만 쓰고, 모서리는 사이트 규칙대로 각지게(반지름 0) 둔다.

   ※ 두 속성 모두 상속된다. html 에만 걸어도 안쪽 스크롤 영역
     (드롭다운 패널, 게시판 표 등)까지 같은 모습이 된다.
--------------------------------------------------------------------------- */

html {
  scrollbar-width: thin;
  scrollbar-color: var(--c-gray-dark) var(--c-paper-sunken);
  /* 썸 / 트랙 순서다. 순서를 바꾸면 트랙이 진해져 화면 가장자리에 검은 띠가 생긴다. */
}

::-webkit-scrollbar {
  width: 10px;    /* 세로 스크롤바 두께 */
  height: 10px;   /* 가로 스크롤바 두께 — 코드 블록·게시판 표에서 쓰인다 */
}

::-webkit-scrollbar-track {
  background-color: var(--c-paper-sunken);
  /* 트랙을 배경보다 한 톤만 눌러 두고, 본문과 만나는 왼쪽 모서리에만 실선을 둔다.
     사방을 두르면 화면 가장자리에 상자가 하나 더 생긴 것처럼 보인다. */
  border-left: 1px solid var(--c-line);
}

::-webkit-scrollbar-thumb {
  background-color: var(--c-gray-dark);
  border-radius: 0;   /* 각진 모서리 — 기본값이지만, 이 프로젝트의 규칙이라 명시한다 */
}

::-webkit-scrollbar-thumb:hover {
  background-color: var(--c-ink);
}

/* 가로·세로 스크롤바가 만나는 우하단 빈 사각형. 비워 두면 흰색으로 남는다. */
::-webkit-scrollbar-corner {
  background-color: var(--c-paper-sunken);
}


/* ==========================================================================
   3. 기본 타이포 · 공통 유틸
   ========================================================================== */

/* ---- 3-1. 모노스페이스 소형 라벨 --------------------------------------------
   섹션 라벨("01 / WORKS"), 메타 정보(날짜·조회수)에 사용.
   대문자 + 넓은 자간이 규칙. 11px 이하로는 내리지 않는다(가독성 하한). */
.label {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  line-height: 1.4;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--color-text-sub);
}

.label--sm { font-size: var(--fs-label-sm); }
.label--xs { font-size: var(--fs-label-xs); }
.label--accent { color: var(--color-accent); }

/* ---- 3-2. 큰 문장 --------------------------------------------------------- */
.display {
  font-size: var(--fs-display);
  font-weight: var(--fw-regular);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
}

.lead {
  font-size: var(--fs-lead);
  line-height: var(--lh-relaxed);
  color: var(--color-text-sub);
}

/* ---- 3-3. 스크린리더 전용 텍스트 ---------------------------------------------
   display:none 은 스크린리더도 읽지 않으므로 쓰면 안 된다.
   1px로 잘라 시각적으로만 감추는 것이 표준 기법.

   .sound_only / .msg_sound_only 를 함께 묶는 이유:
   우리가 쓰는 이름은 .sr-only 지만, 그누보드 코어와 플러그인이 만들어 내는
   HTML 에는 .sound_only 가 박혀 있다. 예를 들어 에디터 플러그인은 textarea
   앞뒤에 <span class="sound_only">웹에디터 시작 / 웹 에디터 끝</span> 을 넣고
   (plugin/editor/smarteditor2/editor.lib.php:24, 54),
   폼 검증 스크립트는 오류 메시지를 <strong class="msg_sound_only"> 로 끼워 넣는다
   (js/wrest.js:332).

   이 정의는 원래 그누보드 기본 CSS(css/default.css:219)에 있는데,
   이 테마는 그 파일을 싣지 않는다. 그래서 정의해 주지 않으면
   "웹 에디터 끝" 같은 문구가 화면에 그대로 노출된다.
   우리 마크업에서는 .sr-only 를 쓰고, 아래 두 이름은 코어 출력물 대응용이다. */
.sr-only,
.sound_only,
.msg_sound_only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- 3-4. 스킵 네비게이션("본문 바로가기") -----------------------------------
   평소엔 보이지 않다가 Tab 첫 진입 시 나타난다.
   .sr-only 와 달리 포커스되면 보여야 하므로 별도 클래스로 둔다.

   ▸ 자리를 헤더 "아래"로 잡은 이유
     헤더(.site-header)는 position: fixed 로 화면 맨 위를 덮고, 그 바 안에는
     왼쪽 끝부터 브랜드명이 들어 있다. 예전처럼 좌측 상단(top/left: 12px)에
     띄우면 스킵 링크가 브랜드명 위에 정확히 겹쳐 앉는다.
     헤더를 아래로 밀어 자리를 만드는 방법도 있지만, 그러려면 부모에서
     :has(.skip-link:focus) 를 봐야 한다 — 이 프로젝트는 구형 브라우저 대응으로
     :has() 를 쓰지 않기로 했다(layout.css 의 .is-open 주석과 같은 이유).
     바 안에는 브랜드·주메뉴·Menu 버튼이 이미 좌·중·우를 다 쓰고 있어 비는 칸도 없다.
     그래서 헤더 높이(--header-h)만큼 내려 바로 아래에 띄운다. 왼쪽은 본문과 같은
     --gutter 에 맞춰, 링크가 가리키는 본문 시작점과 세로줄이 맞는다.

   ▸ 숨기는 방법을 left: -9999px 에서 opacity 로 바꾼 이유
     -9999px 에서 12px 로 이동시키면 전환을 걸었을 때 화면을 가로질러 날아오고,
     전환을 안 걸면 툭 튄다. opacity 는 자리를 그대로 둔 채 사라지므로
     짧은 거리(-8px)만 움직이는 자연스러운 등장을 만들 수 있다.
     visibility: hidden 은 쓰면 안 된다 — 그 값은 요소를 포커스 대상에서 빼버려
     Tab 으로 잡히지 않는다. 스킵 링크가 존재 이유를 잃는다.
     대신 안 보이는 동안 마우스가 눌리지 않도록 pointer-events 를 끈다. */
.skip-link {
  position: fixed;
  top: var(--header-h);
  left: var(--gutter);
  z-index: var(--z-skip);
  padding: var(--sp-3) var(--sp-5);
  background-color: var(--c-ink);
  color: var(--color-text-invert);
  font-size: var(--fs-sm);
  text-decoration: none;

  opacity: 0;
  transform: translateY(-8px);
  pointer-events: none;

  /* 나타날 때(--dur-base)보다 사라질 때가 빨라야 한다.
     Tab 을 연달아 누르는 사용자에게 잔상이 오래 남으면 따라오는 것처럼 보인다.
     (모션 최소화 설정에서는 5-1 의 전역 규칙이 이 시간을 0.01ms 로 덮어
     즉시 나타나고 즉시 사라진다 — 여기서 따로 처리하지 않는다) */
  transition:
    opacity   var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.skip-link:focus {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
  color: var(--color-text-invert);
  transition-duration: var(--dur-base);
}

/* ---- 3-5. 포커스 표시 -------------------------------------------------------
   :focus-visible 은 "키보드로 이동했을 때"만 링을 그린다.
   마우스 클릭 시엔 안 나와서 디자인을 해치지 않으면서 키보드 접근성은 지킨다.
   ※ outline 을 none 으로 지우는 코드는 이 프로젝트에서 금지. */
:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* focus-visible 미지원 구형 브라우저 폴백: 최소한 기본 outline은 남긴다 */
@supports not selector(:focus-visible) {
  :focus {
    outline: 2px solid var(--color-focus);
    outline-offset: 3px;
  }
}

/*
 * 스킵 네비게이션 목적지 — 위 "outline:none 금지" 규칙의 유일한 예외다.
 *
 * 왜 예외인가
 * <main> 에는 tabindex="-1" 이 붙어 있다(theme/portfolio/head.php).
 * 그게 없으면 "본문 바로가기"를 눌러도 포커스가 body 로 되돌아가 다음 Tab 이
 * 헤더부터 다시 시작한다 — 건너뛰라고 만든 링크가 아무것도 건너뛰지 못한다.
 *
 * 그런데 그렇게 옮겨진 포커스를 크롬은 :focus-visible 로 친다(실측 확인).
 * 그러면 본문 전체를 2px 아웃라인이 감싼다. 화면 하나를 통째로 두르는 테두리는
 * 위치를 알려주기는커녕 무엇이 선택됐는지 흐리게 만든다.
 *
 * 금지 규칙이 지키려는 것은 "Tab 으로 닿는 조작 요소의 위치 표시"인데,
 * 이 요소는 Tab 순서에 없고(-1) 조작 대상도 아니다. 사용자가 스스로 고른
 * 목적지라 위치를 다시 알려줄 필요도 없다. 그래서 여기서만 지운다.
 *
 * 범위를 main[tabindex="-1"] 로 좁힌 이유: #content 로 잡으면 나중에 다른
 * 요소에 그 id 가 붙었을 때 조용히 따라간다.
 */
main[tabindex="-1"]:focus,
main[tabindex="-1"]:focus-visible {
  outline: none;
}

/* ---- 3-6. 색 반전 섹션 --------------------------------------------------------
   섹션에 .is-inverted 만 붙이면 그 안의 모든 자식이 자동으로 어두운 배색이 된다.
   자식마다 색을 다시 지정하지 않아도 되는 이유는, 자식들이 원색이 아니라
   시맨틱 토큰(--color-text 등)을 참조하고 여기서 그 토큰만 바꿔치기하기 때문이다.
   → CSS 변수의 상속(cascade)을 이용한 테마 전환 패턴. */
.is-inverted {
  --color-bg:            var(--c-ink);
  --color-bg-raised:     var(--c-ink-soft);
  --color-bg-sunken:     var(--c-ink);
  --color-text:          var(--c-paper);
  --color-text-sub:      var(--c-line);   /* #DCD5CB — 시안의 잉크 배경 위 본문색 (대비 11:1) */
  --color-text-muted:    var(--c-gray);
  --color-border:        rgba(247, 244, 239, 0.16);
  --color-border-strong: rgba(247, 244, 239, 0.28);
  --color-focus:         var(--c-paper);

  background-color: var(--color-bg);
  color: var(--color-text);
}

/* 반전 영역에서 버건디는 명도 대비가 부족(2.4:1)하므로 링크는 본문색 + 밑줄로 */
.is-inverted a {
  color: var(--color-text);
  text-decoration: underline;
  text-underline-offset: 3px;
}


/* ==========================================================================
   4. 반응형 브레이크포인트 (3구간 고정 · 모바일 우선)
   --------------------------------------------------------------------------
     모바일    ~  767px   ← 위쪽 기본 스타일이 곧 모바일 스타일
     태블릿   768 ~ 1023px
     데스크톱 1024px ~

   ※ 미디어쿼리 조건식에는 var()를 쓸 수 없다(CSS 변수는 계산 시점이 늦다).
     그래서 px 값을 직접 적는다. 임의 구간을 추가하지 않는 이유이기도 하다.
   ========================================================================== */

/* ---- 4-1. 태블릿 : 768px ~ ------------------------------------------------ */
@media (min-width: 768px) {
  :root {
    --grid-cols: 8;
  }
}

/* ---- 4-2. 데스크톱 : 1024px ~ --------------------------------------------- */
@media (min-width: 1024px) {
  :root {
    --grid-cols: 12;

    /* 화면이 넓으면 앵커 도착점도 조금 더 여유 있게.
       토큰 하나만 바꾸면 html 의 scroll-padding, [id] 의 scroll-margin,
       그리고 layout.css 의 .l-section[id] 보정까지 전부 따라온다. */
    --anchor-offset: calc(var(--header-h) + var(--sp-6));
  }
}


/* ==========================================================================
   5. 사용자 환경 대응
   ========================================================================== */

/* ---- 5-1. 모션 최소화 ------------------------------------------------------
   CLAUDE.md 접근성 필수 항목. 전정기관 장애 사용자에게 큰 모션은 통증을 준다.
   0s가 아니라 0.01ms를 쓰는 이유: 완전히 0으로 만들면 transitionend/animationend
   이벤트가 발생하지 않아, 그 이벤트에 의존하는 JS가 멈춰버리기 때문이다. */
@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;
    /* 시간뿐 아니라 지연도 지워야 한다. 지연이 남으면 요소가 사라지거나 나타나는
       시점만 늦춰져, 모션은 없는데 반응이 굼뜬 화면이 된다.
       (맨 위로 버튼의 visibility 지연이 여기 걸린다 — layout.css .to-top) */
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
}

/* ---- 5-2. 고대비 모드 ------------------------------------------------------ */
@media (prefers-contrast: more) {
  :root {
    --color-text-sub:   var(--c-text);
    --color-border:     var(--c-line-strong);
  }
}

/* ==========================================================================
   6. 인쇄
   포트폴리오 페이지를 PDF로 저장하는 경우를 위한 최소 처리.
   ========================================================================== */

@media print {
  body {
    background: #fff;
    color: #000;
  }

  .skip-link,
  nav {
    display: none;
  }

  a {
    color: #000;
    text-decoration: underline;
  }
}
