# Changelog

모든 주요 변경 사항은 이 파일에 기록됩니다.

형식은 [Keep a Changelog](https://keepachangelog.com/ko/1.0.0/)를 따르며,
[유의적 버전](https://semver.org/lang/ko/)을 준수합니다.

---

## [Unreleased]

---

## [2.4.1] - 2026-10-21

### 수정
- **내 색상에서 견본에 없는 색이 견본 이름으로 불리던 문제**: 추천 색이나 직접 고른 색처럼 견본에 없는 색의 이름을 명도로만 붙여, 예를 들어 검정 배경에서 [배경색 바꾸기]로 나온 `#bebebe`가 견본 '연회색'(`#e8e8e8`)과 같은 '연회색'으로 표시·낭독됐다. 서로 다른 색이 같은 이름이라 같은 색으로 오해할 수 있었다 (2.3.11부터). 무채색은 견본 이름(검정·진회색·연회색·흰색) 대신 '아주 어두운 회색·어두운 회색·회색·밝은 회색·아주 밝은 회색'으로 부르고, 그래도 견본 이름과 겹치면(예: 견본에 없는 노란색이 '노랑') '노랑 계열'처럼 구분해 부르도록 수정. 6개 언어 모두 같은 규칙이며, 견본과 정확히 같은 색은 지금처럼 견본 이름으로 부른다

---

## [2.4.0] - 2026-10-21

### 변경
- **내 색상 추천에서 바꿀 쪽을 고를 수 있게**: 대비가 7:1에 못 미칠 때 추천 카드가 방금 바꾼 쪽의 반대편 하나만 추천하던 것을, '글자색을 바꾸는 안'과 '배경색을 바꾸는 안'을 함께 보여 주고 고르게 바꿨다. 두 안 모두 남는 쪽 색을 그대로 두고 바꿀 쪽의 색조를 유지한 채 명도만 조정해 7:1에 맞춘다(불가능하면 검정·흰색, 이때도 4.58:1 이상). 줄마다 그쪽을 바꿨을 때의 조합 칩, 추천 색 이름과 대비, [글자색 바꾸기]·[배경색 바꾸기] 버튼이 있고, 방금 고른 색을 지키는 안(반대편)을 위에 두고 강조한다. 누른 쪽 슬롯으로 포커스가 이동하며, 낭독도 두 안을 함께 읽는다. 카드가 뜨는 조건(직접 고른 쪽은 자동 추천에서 제외, 대비 4.5:1 미만이면 [추천 받기])은 그대로
- **내 색상 견본을 슬롯당 12색에서 8색으로 줄임**: 배경색은 흰색·크림·연노랑·연파랑·연회색·진회색·남색·검정, 글자색은 검정·진갈색·남색·진회색·흰색·연회색·노랑·하늘색. 견본 조합 6개에 쓰인 색은 모두 남겼고, 밝은 색과 어두운 색을 어떻게 짝지어도 7:1 이상이다. 패널 폭에서는 4칸 2줄로 보인다. 빠진 색(살구·연분홍·연보라·민트·먹색·진초록·크림 글자·호박색)을 이미 저장한 사용자도 그대로 동작하며 견본 체크만 비고 색상 코드 칸에 그 색이 보인다. 쓰이지 않게 된 색 이름 로케일 키(6개 언어)는 제거

---

## [2.3.12] - 2026-10-21

### 수정
- **아이콘 보기·축소 상태에서 라디오 포커스 링이 보이지 않던 문제 (WCAG 2.4.7)**: 라디오는 opacity 0·1px로 숨기고 포커스를 짝 라벨의 외곽선(`outline-offset: 2px`)으로 그리는데, 라벨을 감싼 목록과 선택 항목이 라벨과 같은 크기에 `overflow: hidden`이라 바깥으로 그린 외곽선이 모두 잘렸다. 키보드로 글자 크기·색상 모드 등의 값을 옮겨도 어디에 포커스가 있는지 보이지 않았다 (2.2.0부터). 외곽선을 라벨 안쪽(`outline-offset: -2px`)에 그리도록 수정. 목록 보기는 원래 잘리지 않아 그대로
- **언어 라디오에서 화살표 한 번마다 언어가 바뀌고 포커스가 사라지던 문제 (WCAG 3.2.2·2.4.3)**: 환경설정의 언어 라디오는 고르는 즉시(`change`) 언어를 바꾸고 패널 전체를 다시 만들었다. 화살표로 다른 언어를 훑기만 해도 패널이 새로 그려져 포커스가 body로 사라지고 개별 설정 탭으로 돌아갔다 (2.0.0부터). 라디오는 고르기만 하고 새 **[언어 적용]** 버튼을 눌러야 바뀌도록 수정. 바꾼 뒤에는 환경설정 탭을 다시 열고 [언어 적용] 버튼에 포커스를 돌려주며, "도구 언어를 바꿨습니다: English (US)"처럼 결과를 새 언어로 알린다. 지금 언어를 그대로 적용하면 패널을 다시 그리지 않는다. 같은 동작은 `WAT.changeLanguage(lang)`으로도 부를 수 있다 (로케일 키 `panel.settings.manage.options.language.apply`, `msg.success.languageChanged` 추가, 6개 언어)
- **위젯 언어를 바꾸면 호스트 페이지 전체의 `<html lang>`이 바뀌던 문제 (WCAG 3.1.1·3.1.2)**: 위젯 언어를 영어로 바꾸면 `document.documentElement`의 `lang`까지 `en-US`로 덮어써, 한국어 페이지 본문 전체를 스크린리더가 영어 엔진으로 읽었다 (2.1.0부터). `<html lang>`은 건드리지 않고 위젯이 만든 요소에만 위젯 언어를 지정하도록 수정: 위젯 컨테이너(패널·열기 버튼 포함), body에 붙는 라이브 리전과 알림 상자. 처음 그릴 때도 지정하므로 페이지 언어와 위젯 언어가 달라도 위젯 문구가 위젯 언어로 읽힌다. 상주 라이브 리전은 알릴 때마다 지금 언어로 갱신한다
- **모달이나 호스트 입력칸에서 누른 Esc에 패널까지 닫히던 문제 (WCAG 2.4.3)**: 페이지 구조·사전 모달에서 누른 Esc가 문서까지 전파되어 모달과 함께 패널이 닫혔고, 포커스는 패널을 연 버튼이 아니라 열기 버튼으로 갔다. 호스트 페이지의 검색창 같은 입력칸에서 누른 Esc에도 패널이 닫혔다 (2.2.0부터). 모달이 처리한 Esc는 전파를 막고, 패널 닫기는 위젯 안에서 누른 Esc 가운데 다른 컨트롤이 처리하지 않은(`defaultPrevented`가 아닌) 것에만 반응하도록 수정
- **페이지 구조에서 항목으로 이동하면 포커스가 사라지던 문제 (WCAG 2.4.3·2.4.6)**: 제목·랜드마크·링크의 [해당 위치로 이동]을 누르면 대화상자만 닫히고 포커스가 body로 사라져, 키보드 사용자는 페이지 처음부터 다시 탭해야 했다 (2.0.0부터). 이동한 대상으로 포커스를 옮기도록 수정. 제목·랜드마크처럼 포커스를 받을 수 없는 요소는 임시로 `tabindex="-1"`을 줬다가 포커스가 떠나면 지우고, 페이지가 원래 준 `tabindex`는 건드리지 않는다. 이동 버튼의 이름이 모두 '해당 위치로 이동'이라 구분되지 않던 점도 "새 소식 해당 위치로 이동"처럼 항목 텍스트를 넣어 고쳤다
- **개별 설정 제목을 눌러 값을 바꿔도 무엇으로 바뀌었는지 알 수 없던 문제 (WCAG 4.1.2·4.1.3)**: 개별 설정 항목의 제목(버튼)을 누르면 라디오 값이 다음으로 넘어가고 스위치가 켜지거나 꺼지지만, 포커스는 제목에 머물고 제목 이름도 그대로라 스크린리더 사용자는 바뀐 값을 들을 수 없었다. 아이콘 보기의 이전/다음 버튼도 같았다 (2.1.0부터). 제목·이전/다음 버튼으로 바꾸면 "글자 크기: 1.5배", "애니메이션 제어: 정지"처럼 바뀐 값을 알리도록 수정. 라디오를 직접 고를 때는 스크린리더가 이미 읽으므로 따로 알리지 않는다
- **알림 상자 글자가 배경과 대비가 부족하던 문제 (WCAG 1.4.3)**: 저장·가져오기 등의 알림은 흰 글자 14px인데 배경이 성공 `#10b981`(2.54:1)·경고 `#f59e0b`(2.15:1)·정보 `#3b82f6`(3.68:1)·오류 `#ef4444`(3.76:1)로 4.5:1에 못 미쳤다 (2.0.0부터). 성공 `#047857`(5.48:1)·경고 `#b45309`(5.02:1)·정보 `#1d4ed8`(6.70:1)·오류 `#b91c1c`(6.47:1)로 수정. 타입별 아이콘은 그대로
- **바닥글 링크의 대비가 부족하던 문제 (WCAG 1.4.3)**: 바닥글의 'DAEGU CYBER UNIVERSITY' 링크(12px 굵게)가 `#0D6EFD` on `#f8f8f8`로 4.24:1이었다 (2.0.0부터). `#0a58ca`(6.06:1)로 수정
- **열기 버튼의 이름이 '열기'뿐이던 문제 (WCAG 2.4.6)**: 페이지 어디서든 탭으로 만나는 열기 버튼의 접근 이름(`aria-label`·`title`)이 '열기'뿐이라 무엇을 여는 버튼인지 알 수 없었다 (2.0.0부터). '웹 접근성 지원 도구 열기'(영어 'Open Web Accessibility Support Tool' 등 6개 언어)로 수정 (로케일 키 `command.openTool` 추가)
- **탭 목록·라디오 그룹 안의 목록 항목이 역할 구조를 깨던 문제 (WCAG 1.3.1)**: 패널 탭(`ul[role=tablist]`)과 개인 옵션 라디오 묶음(`ul[role=radiogroup]`) 안의 `li`가 목록 항목 역할을 그대로 가져, 탭·라디오가 그룹에 직접 속하지 않고 목록 밖 목록 항목이 생겼다(axe `aria-required-children`·`aria-required-parent`·`listitem` 위반, 탭 목록은 2.0.0부터, 라디오 그룹은 2.1.0부터). 이 `li`에 `role="none"`을 주도록 수정. 스위치·버튼 항목의 목록은 그대로
- **프로필 옵션의 빈 라벨과 언어 변경 뒤 바뀌는 프로필 이름 (WCAG 1.3.1·4.1.2)**: 움직임 민감 프로필의 옵션을 열면 애니메이션·미디어 정지 체크박스에 이름이 없었다. 라벨을 설정 키로 찾는데 이 두 항목은 로케일 그룹명이 달라(`animationControl`·`mediaControl`) 빈 문자열이 됐기 때문 (2.2.0부터). 개별 설정과 같은 이름('애니메이션 제어'·'미디어 제어')이 붙도록 수정. 또 언어를 바꾸면 저시력 프로필 이름이 '시각 장애'로 덮어써져, 같은 이름의 프로필이 두 개로 보이고 읽혔다 (2.0.0부터). 프로필마다 자기 이름으로 맞추도록 수정
- **페이지 구조·사전 대화상자와 음성 명령 상태창의 언어 (WCAG 3.1.2)**: 위의 `<html lang>` 수정으로 body에 붙는 대화상자와 상태창은 위젯 언어와 상관없이 페이지 언어로 읽히게 됐다. 그 전(2.1.0부터)에는 반대로 페이지 구조 목록의 제목·링크 같은 페이지 글까지 위젯 언어로 읽혔다. 대화상자 안에 페이지 글·사전 결과가 섞여 있어 통째로 위젯 언어를 달지 않고 나눠 지정하도록 수정: 페이지 구조는 대화상자에 위젯 언어를 달고, 목록의 제목·랜드마크 이름·링크 글자는 그 글이 쓰인 요소의 언어(가장 가까운 `lang`, 페이지에 지정이 없으면 언어 미상 `lang=""`)로 감싼다. 사전 결과는 표제어·뜻풀이·발음을 페이지 언어로 두고 닫기 버튼·발음 라벨에만 위젯 언어를 단다. 음성 명령 상태창은 위젯 문구뿐이라 위젯 언어로 읽히고, 켜 둔 채 언어를 바꿔도 다음 상태부터 따라간다. 대화상자는 열 때마다 지정하므로 언어를 바꾼 뒤 연 대화상자도 새 언어를 따른다. 페이지 구조의 이동 버튼은 이름에 항목 텍스트와 위젯 문구가 함께 들어 있어 위젯 언어로 둔다
- **내 색상의 잘못된 색상 코드가 음성으로 안내되지 않던 문제 (WCAG 3.3.1·4.1.3)**: 잘못된 코드를 넣으면 입력칸에 `aria-invalid`와 오류 문구(`aria-describedby`)가 붙지만, Tab으로 벗어나며 확정하면 포커스가 이미 다음 컨트롤에 있어 스크린리더 사용자는 오류를 듣지 못했다 (2.3.11부터). 확정(포커스 이동·Enter) 때 "배경색 색상 코드가 올바르지 않습니다. #과 16진수 6자리(또는 3자리)로 입력해 주세요."처럼 어느 칸이 왜 틀렸는지 라이브 리전으로 한 번 알리도록 수정. 직전에 견본을 바꿔 대기 중이던 안내는 취소해 오류 안내를 덮지 않는다 (로케일 키 `panel.settings.manage.options.customColors.hexErrorAnnounce` 추가, 6개 언어)
- **`data-wat-container`를 지정해도 위젯이 늘 `<body>` 맨 앞에 들어가던 문제**: 자동 초기화(`data-wat-auto`)는 `data-wat-container` 값을 `containerSelector` 옵션으로 넘기는데, 삽입 위치를 정하는 코드는 `containerTargetSelector`만 읽어 이 값이 무시됐다. 생성자 JSDoc 예시대로 `new WAT({ containerSelector: '#…' })`를 써도 같았다 (`data-wat-container`가 생긴 2.1.0부터). `containerSelector`를 `containerTargetSelector`의 별칭으로 받도록 수정. 둘 다 주면 `containerTargetSelector`가 우선하고, 위젯은 지정한 요소 안 맨 앞(`containerTargetPosition: 'after'`면 맨 뒤)에 들어간다. 생성자 JSDoc 예시도 `containerTargetSelector`로 고쳤다

---

## [2.3.11] - 2026-10-21

### 추가
- **내 색상 (WCAG 2.2 1.4.8 시각적 표현)**: 배경색과 글자색을 사용자가 직접 고르는 다섯 번째 색상 모드. 환경설정 탭의 '내 색상'에서 견본 조합 6개, 슬롯마다 견본 12색, 색 선택기, 색상 코드(`#` 생략·3자리 허용)로 고르고, 개별 설정의 색상 모드에서 '내 색상'으로 켜고 끈다. 저장한 색이 없으면 크림 바탕 진갈색 글자(12.0:1)로 바로 동작하므로 색상 모드 제목을 눌러 순환하다 '내 색상'이 골라져도 오류가 없다
- **명도 대비 표시와 짝 색 추천**: 한쪽 색을 바꾸면 상대편 색을 7:1(AAA)에 맞춰 추천하고 [추천색 적용]·[직접 고를게요]로 고른다. 추천은 상대편 색의 색조를 유지한 채 명도만 조정하고, 같은 색조로 7:1이 불가능하면 검정·흰색 중 대비가 큰 쪽을 추천한다(이때도 4.58:1 이상). 승인한 색도 언제든 직접 바꿀 수 있다. 직접 고른 쪽은 자동 추천 대상에서 빼 추천이 번갈아 뜨지 않게 했고, 두 색을 모두 직접 골랐는데 대비가 4.5:1 미만이면 [추천 받기]가 나타난다. 대비 수치는 소수 첫째 자리에서 내려 표시한다(4.49를 '4.5'로 보이지 않게)
- **낮은 대비 저장 정책**: 4.5:1 미만 조합도 저장할 수 있고 경고 알림만 띄운다. 눈부심에 민감하거나 낮은 대비가 편한 사용자가 있기 때문
- **링크·보조색 자동 계산**: 링크색은 배경과 4.5:1 이상이면서 본문과 3:1 이상 구분되는 색으로 계산하고, 본문과 색으로 구분되지 않는 조합이면 '내 색상'에서만 링크에 밑줄을 긋는다. 입력 안내문 등에 쓰는 보조 글자색·배경색도 4.5:1을 지키도록 계산한다
- **스크린리더 안내**: 견본은 슬롯마다 네이티브 라디오 묶음이고, 색은 hex 대신 견본 이름이나 대략적인 색 이름('아주 어두운 노랑')으로 읽는다. 추천과 대비 안내는 공용 라이브 리전으로 한 번만 낭독한다(화살표로 견본을 훑을 때 연달아 읽지 않도록 0.5초 대기). 색 칩과 미리보기는 Windows 고대비 모드에서도 고른 색 그대로 보인다
- **저장과 이전**: 색은 새 저장 키 `watCustomColors`(`{v:1, bg, fg}`)에 둔다. 설정 내보내기·가져오기·초기화에 함께 포함되며, 불러올 때 `#rrggbb` 형식이 아니면 무시한다. 같은 출처 iframe에도 반영되고, 6개 언어를 지원한다. 사이트 설정에서 색상 모드를 끄면(`colorTheme: false`) 편집기도 숨긴다

### 수정
- **'창 축소' 상태가 다른 설정을 바꾸면 사라지던 문제**: 축소 상태(`isMinimized`)는 `saveMinimizeState`가 `watSettings`에 따로 끼워 넣는데, 설정 저장(`savePreferences`)이 화면에서 모은 14개 항목으로 같은 키를 통째로 덮어써 이 값을 지웠다. 그래서 툴바를 축소한 뒤 글자 크기 같은 설정을 하나라도 바꾸면 새로고침 때 펼쳐진 상태로 돌아왔다. 저장할 때 기존 값의 `isMinimized`를 이어받도록 수정. 축소한 적이 없으면 이전처럼 이 항목을 기록하지 않는다 (재방문 시 축소 상태를 복원하기 시작한 2.3.6부터)
- **색상 모드 '반전'과 채도 변경을 함께 켜면 페이지가 반전되지 않던 문제**: 반전(`:root[data-color-theme="reverse"]`)과 채도 변경(`:root[data-saturation="…"]`)은 둘 다 문서 루트의 `filter`를 쓰는데 특이도가 같아, 뒤에 선언된 채도 필터가 `invert(1)`을 덮었다. 그래서 반전을 켠 채 채도를 낮게·높게·흑백·적색약 보정·녹색약 보정 중 하나로 바꾸면 페이지는 반전되지 않았다 (2.0.0부터, 색약 보정은 2.2.0부터). 2.2.0부터는 반전 모드에서 이미지·영상과 위젯을 다시 뒤집는 보정 규칙은 그대로 남아, 이미지와 툴바만 색이 뒤집혀 보였다. 반전과 채도 값마다 조합 규칙(예: `filter: invert(1) grayscale(100%)`)을 두어 두 효과가 함께 적용되도록 수정. 반전을 먼저 적용하므로, 다시 뒤집은 이미지·영상과 위젯은 채도만 바꿨을 때와 같은 색으로 보인다

---

## [2.3.10] - 2026-10-13

### 보안
- **화면 낭독이 비밀번호 칸의 값을 소리 내 읽던 문제**: 포커스 탐지와 자동 읽기가 입력란을 읽을 때 `type="password"` 칸도 일반 입력란처럼 값을 붙여 읽었다(예: "비밀번호 Secret!23"). 웹 음성은 스피커로 나오므로 공용 PC에서는 옆 사람이 비밀번호를 들을 수 있다. 비밀번호 칸은 값을 읽지 않고 라벨만 읽도록 수정. 라벨이 없으면 안내문(placeholder)이나 '비밀번호 입력란'(6개 언어)을 읽는다. 비밀번호 칸으로 보는 기준은 `type="password"`이거나 `autocomplete`가 `current-password`·`new-password`·`one-time-code`인 칸이다(비밀번호 보기 단추로 type이 text로 바뀐 칸 포함). 자동 읽기와 포커스 탐지의 클릭 낭독은 2.0.0부터 그랬고, 2.3.7에서 추가한 Tab 낭독에도 나타났다

### 수정
- **화면 낭독 버튼 크기가 제각각이던 문제**: 화면 낭독의 네 버튼 가운데 포커스 탐지(돋보기) 버튼은 아이콘이 24px이라 글리프 버튼(▶ ◁ ▷)보다 넓게, 호스트 글꼴에 따라서는 높게도 그려졌다. 높이가 다르면 글리프 버튼이 줄 가운데에 작게 떠서 버튼 묶음의 테두리가 어긋났다(b.dcu.ac.kr 아이콘 보기에서 41.6×27px 대 31.6×22px). 버튼 묶음의 칸 너비를 똑같이 나누고 최소 높이(26px)를 두어, 호스트의 글꼴 줄 높이나 button 여백과 상관없이 모든 버튼이 같은 크기로 한 줄을 채우도록 수정. 돋보기 아이콘은 20px로 줄여 글리프와 크기를 맞췄다. 페이지 스크롤·음성 인식·페이지 구조 버튼도 같은 높이가 된다 (2.0.0부터)

### 문서
- **설치 안내를 자동 업데이트되는 CDN 주소로 변경**: README·설치 안내(install-guide.html)의 CDN 예시를 `@main/dist/webAccTools.js`에서 `@2/dist/webAccTools.standalone.min.js`로 바꿨다. `@main`은 릴리스 전 코드까지 바로 나가므로 쓰지 않도록 안내하고, `@2`·`@2.3`·`@v2.3.10`의 차이와 새 버전이 퍼지기까지 걸리는 시간(최대 7일, jsDelivr 퍼지 도구로 앞당김)을 적었다. CDN에서 `data-wat-config`에 상대 경로를 쓰면 jsDelivr 주소 기준이 된다는 점도 추가
- **다른 도메인에서 불러올 때 안내 추가**: 파일과 페이지의 도메인이 다르면 위젯이 그 서버에서 받는 언어 파일·아이콘에 허용 헤더(CORS)가 필요하다. 헤더가 없을 때 standalone은 한국어만 동작하고 `webAccTools.js`는 패널 글자가 비는 점, Apache·IIS·Nginx 설정 예시를 README에 적었다

---

## [2.3.9] - 2026-10-07

### 수정
- **재방문 시 저장된 프로필의 애니메이션·미디어 정지가 다시 켜지지 않던 문제**: 움직임 민감 프로필을 켠 뒤 새로고침하거나 다른 페이지로 이동하면 프로필 토글은 켜짐으로, 채도(낮게)도 그대로 돌아오는데 애니메이션과 미디어는 멈추지 않았다. 개별 설정의 애니메이션 제어·미디어 제어 스위치도 꺼짐으로 보였고, 켜짐으로 보이는 토글을 누르면 프로필이 꺼져 두 번 눌러야 다시 적용됐다 (2.2.0부터). 토글형 값은 저장 설정(`watSettings`)에 들어가지 않는데, 프로필 복원은 설정값이 모두 저장값에서 돌아온다고 보고 토글·체크박스 표시만 되살렸기 때문. 프로필을 복원할 때 그 프로필이 켰던 토글형 항목(애니메이션 정지·미디어 정지·음소거)을 다시 켜도록 수정. 스위치 표시는 프로필을 켤 때와 같이 `change` 없이 맞추므로 미디어 정지 같은 동작이 두 번 실행되지 않고, 프로필 옵션에서 체크를 뺀 항목은 켜지 않는다. 포커스 낭독 자동 시작 같은 동작형 항목은 지금처럼 프로필을 켤 때만 실행

---

## [2.3.8] - 2026-09-29

### 수정
- **스위치 트랙을 눌러도 켜지거나 꺼지지 않던 문제**: 개별 설정 스위치(미디어 제어·미디어 볼륨 제어·애니메이션 제어·사전 검색)의 트랙은 숨겨 둔 `input[role=switch]`에 `for`로 연결된 라벨(`label.switch-label`)인데, 이 라벨에 토글 리스너가 따로 붙어 있어 브라우저 기본 동작과 합쳐 한 번 누르면 두 번 토글됐다(`change`가 켜짐→꺼짐으로 2회). 상태는 그대로인데 부수 효과만 두 번 실행되어, 미디어 제어는 재생 중이던 미디어가 멈췄는데도 스위치는 꺼짐으로 남았다. 라벨 리스너를 제거해 브라우저 기본 동작만으로 한 번 토글되도록 수정. 제목(role=button) 클릭·키보드 조작과 비활성 스위치 처리는 그대로 (2.0.0부터 있던 문제)
- **스위치 옆 상태 문구와 `aria-checked`가 실제 상태와 어긋나던 문제**: 개별 설정 스위치(미디어 제어·미디어 볼륨 제어·애니메이션 제어·사전 검색)를 만들 때 켜짐 여부와 관계없이 켜짐 문구를 넣어, 새로 불러온 페이지에서 꺼진 미디어 제어가 '정지', 미디어 볼륨 제어가 '음소거'로 보였다. 한 번 켰다 끄면 '재생가능'·'음소거 해제'로 바뀌어, 같은 꺼짐 상태가 조작 이력에 따라 다르게 표시됐다 (2.0.0부터). 프로필을 켜고 끌 때는 체크 상태만 바꿔, 프로필로 켠 스위치가 화면에는 켜짐인데 `aria-checked="false"`와 이전 문구가 남아 스크린리더가 꺼짐으로 읽었다 (2.2.0부터). 상태 문구와 `aria-checked`를 체크 상태에 맞추는 처리를 한곳으로 모아, 패널을 만들 때·사용자가 켜고 끌 때·프로필 적용과 해제(첫 방문 시 OS 모션 감소 반영 포함)에 같이 쓰도록 수정. 프로필 쪽은 `change` 이벤트 없이 표시만 맞추므로 미디어 정지·음소거 같은 동작이 두 번 실행되지 않는다
- **`updatePersonalSettingsUI('checkbox', …)`로 스위치 값을 맞추면 `aria-checked`·상태 문구가 그대로 남던 문제**: 체크 상태만 바꾸고 표시는 맞추지 않아, 켜도 `aria-checked="false"`와 꺼짐 문구가 남았다. 위 항목에서 한곳으로 모은 스위치 표시 처리를 같이 쓰도록 수정. `change` 이벤트 없이 표시만 맞추므로 미디어 정지 같은 동작이 다시 실행되지 않는다. 패널 안에서는 이 형태로 부르는 곳이 없어 화면 동작에는 변화가 없고, 이 메서드를 직접 부르는 코드에만 해당

### 변경
- **사전 서버가 없는 사이트에서 사전 검색 항목을 숨김**: 2.3.7에서는 config에 사전 서버(`api.dictionary.serverEndpoint`)가 없으면 사전 검색 스위치를 '사용 불가'로 비활성 표시했다. 동작할 수 없는 기능을 패널에 남기지 않도록 항목 자체를 그리지 않게 바꾸고, 단축키 `Alt+Shift+D`도 키를 가로채지 않고 무시한다. 사전 서버가 설정된 사이트는 이전과 같다. 쓰이는 곳이 없어진 '사용 불가' 문구(`panel.personal.options.diction.options.unavailable`, 6개 언어)와 비활성 스위치 스타일은 제거
- **데모 사이트에서 사전 검색 항목을 숨김**: 데모는 `config.example.json`을 그대로 `config.json`으로 배포해, 자리 표시자 사전 주소(`your-server.example`)가 설정된 것으로 인식됐다. 스위치가 켜지는데 검색할 때마다 실패했으므로, Pages 워크플로에서 데모용 config를 만들 때 사전 주소를 비워 모든 예제 페이지에서 사전 검색 항목이 나타나지 않게 함 (라이브러리 배포물에는 변화 없음)

### 제거
- **호출되지 않던 스위치 리스너 설정 메서드 `setCheckboxListeners()`**: 개별 설정 스위치의 `change`는 패널이 문서에 거는 위임 핸들러가 처리해 쓰이는 곳이 없던 메서드. 같은 처리를 따로 복제한 사본이라 `aria-checked`를 맞추지 않았고, 위임 핸들러와 함께 걸리면 한 번 조작에 동작이 두 번 실행되는 구조였다(사전 검색은 두 번 반전되어 스위치와 실제 상태가 어긋남). README 등에 공개 API로 안내한 적이 없어 제거했다. 패널 동작에는 변화 없음
- **`updatePersonalSettingsUI()`의 `'button'` 타입 처리와 개별 설정 항목의 `active` 클래스 토글**: 버튼형 개별 설정(페이지 스크롤·화면 낭독·음성 인식·페이지 구조)은 `<button>`만 그려 이 메서드가 찾는 `input`이 없으므로 `'button'` 분기에는 도달할 수 없었고, 이 타입으로 부르는 곳도 없었다. 호출 후 항목(`.personalOpt_item`)에 `active` 클래스를 붙이던 처리는 이 클래스를 쓰는 스타일·코드가 없었고, 라디오는 값을 기본값으로 되돌려도 `active`가 붙어 있어 상태를 나타내지도 못했다. 둘 다 README 등에 안내한 적이 없어 제거했다. 패널 동작에는 변화 없음

---

## [2.3.7] - 2026-09-29

### 수정
- **호스트 페이지에서 패널 제목이 어둡게 보이던 문제**: 제목 글자색을 헤더(`#wat_header`)의 흰색 상속에만 맡겨, 호스트 CSS의 전역 규칙(예: `* { color: #333 }`)이 제목에 직접 적용되면 파란 헤더 위 글자가 #333으로 덮였다(대비 약 1.4:1, WCAG 1.4.3). 제목에 흰색을 직접 지정하고, 같은 구조였던 알림 메시지·아이콘과 음성 명령 상태 문구도 상자의 글자색을 직접 상속하도록 수정
- **'창 축소'에서 기능 아이콘이 사라지던 문제**: 2.3.6에서 축소 상태를 200×52px 헤더 바로 바꾸면서 원래 설계인 아이콘 띠(200px 폭, 기능 아이콘과 조작 버튼 1열)가 없어졌다. 아이콘 띠로 되돌리고, 목록 보기에서도 아이콘 배치를 쓰도록 해(이전 아이콘 띠는 목록 보기에서 조작 영역이 31px로 눌려 글자 단위로 줄바꿈됐다) 두 보기 모드가 같은 모습으로 축소된다. 환경설정 탭을 보던 중 축소하면 개별 설정 탭으로 전환. 탭·푸터는 계속 `display:none`으로 접어 탭 순서에 남지 않음
- **화면 낭독 '포커스 탐지'가 아무것도 읽지 않던 문제**: 위젯 UI 여부를 `wat-` 접두사 클래스로 판별해, 위젯이 호스트 요소에 붙이는 마킹 클래스(동적 스타일용 `wat-dyn-*`, 2.3.5부터 기본 설정에서 `body`에 붙는 `wat-apply`)까지 위젯으로 오인했다. 그 결과 페이지 전체가 낭독 대상에서 빠졌다. 위젯이 만든 UI에 붙이는 제외 표식(`.wat-exclude`)으로만 판별하도록 수정
- **사전 서버가 없는 사이트에서도 사전 검색 스위치를 켤 수 있던 문제**: config에 `api.dictionary.serverEndpoint`가 없으면 검색이 동작하지 않는데, 사전 활성 여부(`api.dictionary.enabled`)가 패널 스위치에 반영되지 않았다. 서버 미설정 시 스위치를 끈 채 비활성화하고 '사용 불가'로 안내(6개 언어). 제목 클릭이나 `toggleDiction()` 호출로도 켜지지 않음

### 추가
- **포커스 탐지의 키보드 포커스 낭독**: 포커스 탐지를 켜면 Tab 키 등으로 포커스가 이동한 요소를 읽는다(링크·버튼·입력은 요소 종류와 함께). 문서의 "포커스된 요소 읽기"와 시각 장애 프로필의 "포커스 낭독 자동 시작"에 맞춘 동작으로, 이전에는 마우스 클릭·선택만 읽었다. 마우스 클릭으로 생긴 포커스는 기존 클릭 낭독이 읽으므로 중복 발화하지 않음

---

## [2.3.6] - 2026-08-26

### 수정
- **'창 축소'가 시각적으로 거의 동작하지 않던 문제**: 높이 축소 규칙이 주석 처리된 채 남아 축소해도 제목·탭만 사라지고 본문이 전체 높이로 그대로 보였다. 축소 상태를 200×52px 헤더 바로 정의 — 본문·푸터를 `display:none`으로 접어 보이지 않는 컨트롤 93개가 탭 순서에 남던 문제(WCAG 2.4.3)와 축소 상태에서 마지막 항목이 푸터에 가려진 채 탭 되던 문제를 함께 해소. 또한 `restoreMinimizeState()`가 정의만 있고 호출되지 않아 저장된 축소 상태가 재방문 시 복원되지 않던 것을 init에 연결해 수정. (참고: 축소 시 폭이 500px로 남는다는 기존 관찰은 비표시 탭에서 트랜지션이 진행되지 않는 측정 환경 문제였고, 화면 표시 중에는 정상적으로 200px로 전환됨을 확인)

---

## [2.3.5] - 2026-08-26

### 수정
- **모달에서 키보드 포커스가 보이지 않는 곳으로 빠지던 문제**: 페이지 구조·사전 검색 다이얼로그를 열면 초기 포커스가 레이어 자신(tabindex=-1)에 있는데, 포커스 트랩이 첫/마지막 요소에서만 개입해 이 상태에서 Shift+Tab 한 번에 포커스가 오버레이 뒤 콘텐츠로 이탈했다. 한 번 나가면 트랩 리스너(레이어 keydown)가 더는 개입하지 못해 가려진 페이지를 계속 탐색하게 되는 문제. 목록 밖 포커스도 경계로 순환시키고, CSS로 숨긴 요소를 순환 경계에서 제외하며, 문서 수준 focusin 안전망(모달 밖으로 나간 포커스 즉시 복귀, teardown 시 해제)을 추가
- **applySelector 대상에 `undefined` 클래스가 붙던 문제**: `Constants.CSS_CLASSES`에 `APPLY` 키가 없어 `classList.add(undefined)`로 문자열 "undefined"가 부여되고 `.wat-apply` 스타일 경로가 무력화됐다. `APPLY`/`EXCLUDE` 상수를 정의하고 제외 클래스도 하드코딩 대신 상수를 쓰도록 정리

---

## [2.3.4] - 2026-08-10

### 수정
- **조작 대상 크기를 WCAG 2.2 기준(24×24)으로 통일**: 프로필 옵션 열기 버튼(24×19), 환경설정 라디오 항목(20×13), 아이콘 모드 선택 라벨(높이 15px)이 새 기준에 못 미쳤다. 최소 크기를 확보해 개인 설정·환경설정을 아이콘/목차 보기 양쪽에서 모두 충족하도록 수정. 두 보기 모드의 조작 요소 166개를 브라우저에서 실측해 미달 0건 확인

---

## [2.3.3] - 2026-08-10

### 수정
- **패널을 끝까지 스크롤해도 마지막 항목이 푸터에 가려지던 문제**: 본문 영역이 `height:100%`로 헤더 높이를 고려하지 않아 패널 아래로 밀리고, 푸터가 `position:absolute`로 그 위를 덮고 있었다. 헤더·본문·푸터를 flex 흐름으로 정리해 본문이 남은 높이만 차지하도록 수정 — 고정 `calc()` 높이 6곳도 함께 제거. 환경설정·개별 설정 × 아이콘·목차 보기 × 최소화 상태를 여러 창 크기에서 확인

---

## [2.3.2] - 2026-08-10

### 제거
- **저장 설정의 '저장 확인' 버튼**: 개발 중 저장 여부를 확인하려고 두었던 버튼으로, 최종 사용자에게는 불필요해 제거했다. 전용 로케일 키(`storage.options.check`, `msg.state`, `msg.info.storageCheck`)도 6개 언어에서 함께 정리

---

## [2.3.1] - 2026-08-10

### 수정
- **프로필 항목 테두리가 여전히 깨져 보이던 문제**: 2.3.0에서 테두리를 `box-shadow` 링으로 바꿨으나, 제목바(`legend`)의 배경이 링 위를 덮어 아래쪽 일부만 보였다. 링 대신 `legend`에 `float`를 주어 rendered legend에서 제외시키는 방식으로 교체 — 테두리 4면이 정상으로 그려진다 (닫힘·펼침 모두 확인)

---

## [2.3.0] - 2026-08-10

### 추가
- **낭독 음성 선택**: 환경설정에서 화면 낭독에 사용할 음성을 고를 수 있습니다. 현재 언어 음성을 먼저 묶어 보여주고, 선택한 음성은 저장되어 다음 방문에 복원됩니다. 음성을 지원하지 않는 브라우저에서는 항목이 표시되지 않으며, 저장된 음성이 없는 기기에서는 브라우저 기본 음성으로 자동 대체됩니다 (6개 언어 라벨)

### 수정
- **프로필 항목 테두리가 깨져 보이던 문제**: 제목바(`legend`)가 폭 전체를 차지해 HTML 명세의 rendered legend 동작에 따라 `fieldset` 위쪽 테두리가 통째로 지워지고 있었다. 테두리를 `box-shadow` 링으로 그려 제목바 영향을 받지 않게 수정
- 프로필 옵션을 펼쳤을 때 컨테이너 밖으로 번지던 진한 그림자를 제목바 구분선으로 교체

### 변경
- 낭독 언어 코드 변환 로직을 TTSManager로 통합 (AutoTTS·BaseTTS 중복 제거)

---

## [2.2.0] - 2026-08-04

### 수정
- **어둡게(dark) 테마에서 텍스트가 보이지 않던 문제**: 배경만 `#333`으로 강제하고 글자색을 지정하지 않아, 원래 어두웠던 텍스트가 같은 색 배경에 묻혔다(호스트 페이지 폼 라벨은 대비 1.00으로 완전 불가시). 전경색 규칙을 추가하고 링크·아이콘 글리프·폼 컨트롤 예외를 분리했다. 자동 측정 기준 패널 46/48 → 0/41, 호스트 16/21 → 0/21 실패
- **`pre`/`code` 본문이 잘려 보이던 문제**: 인라인 요소에 강제된 배경 상자가 줄마다 윗줄 글자를 덮었다. 인라인 요소 배경을 투명 처리해 해소
- **CI dist 드리프트 게이트 상시 실패**: Windows(CRLF)에서 빌드하면 인라인되는 CSS·`ko.json`이 LF 체크아웃 환경과 1400곳 달라졌다. 텍스트 자산을 LF로 정규화해 빌드 산출물을 플랫폼 독립적으로 변경
- `check-css-selectors.mjs`가 `:is()`·`[attr="a,b"]` 내부 쉼표를 셀렉터 구분자로 잘못 인식하던 문제
- **CSS 셀렉터·경로 불일치로 죽어 있던 스타일 복구**: `data-wat-(color-theme|read-guide|screen-scale)` 셀렉터 19곳이 JS가 세팅하는 속성명과 달라 TTS 하이라이트·사전 알림의 테마 대응이 미적용되던 문제. iframe CSS 주입도 상수 경로 오기로 항상 건너뛰어지고 있었다. 회귀 방지 테스트 추가
- **프로필 해제 비대칭**: 저시력 프로필 해제 시 자간이 복원되지 않고, 프로필이 건드리지 않은 설정(이미지 변환·애니메이션 정지)을 강제 해제하던 문제
- **언어 설정 유실**: 저장된 언어가 dataset에 복원되지 않아 다른 설정을 저장하면 언어가 기본값으로 덮어써지던 문제
- **포커스 트랩 결함**: 모달 내용이 바뀌어도 설치 시점 요소만 순환하고 disabled 요소를 경계로 잡던 문제 — keydown 시 재조회로 전환
- **TTS 알림이 화면 높이만큼 늘어나던 문제**: 중복 정의된 CSS의 top/bottom 충돌. 알림 스타일을 CSS 단일 출처로 정리하고 무시되던 등장 애니메이션 복구
- **프로필 토글 ARIA**: `role=switch` 상태를 `aria-checked`로 전달(기존 `aria-pressed`는 스크린리더에 미전달), 접근명이 전부 "꺼짐"으로 낭독되던 `aria-labelledby` 오지정 수정, 옵션 아코디언을 disclosure 패턴(`aria-expanded`+`aria-controls`)으로 정정

### 변경
- **밝게(light) 테마**: 전역 `brightness(1.3)` 필터(글자까지 밝아져 대비가 오히려 하락)를 어둡게 테마와 대칭인 고대비 라이트 팔레트로 교체
- **반전(reverse) 테마**: 이미지·영상 등 미디어와 위젯 UI를 재반전해 원본 색 유지
- **다크/밝게 평탄화의 위젯 자기 보호**: `.wat-exclude` 트리를 평탄화에서 제외해 위젯 패널·읽기 가이드·알림이 테마에 침식되지 않도록 변경. 호스트 페이지용 제외 탈출구 `.designWrap`은 하위 트리까지 확장
- **단축키 변경**: `Shift+T/D/S` → `Alt+Shift+T/D/S` (WCAG 2.1.4 문자 키 단축키 해소). `settings.ui.keyboardShortcuts: false`로 비활성화 가능
- **알림 낭독을 상주 라이브 리전 방식으로 전환**: 리전을 텍스트와 함께 삽입하면 일부 스크린리더가 첫 알림을 놓치는 문제 대응
- 다크 테마 서브 배경 `#666` → `#4a4a4a` (서브 텍스트와 3.6:1 → 5.5:1)

### 추가
- **패널에서 어둡게 테마 선택 활성화**: 비활성 사유였던 다크모드 결함이 모두 수정되어 색상 모드 라디오에서 선택 가능
- **OS 접근성 설정 자동 반영**: 첫 방문 시 OS 다크 모드·모션 감소 설정을 초기값으로 적용 (`settings.ui.respectOsPreferences: false`로 해제)
- **브라우저 언어 자동 감지**: 저장된 언어가 없으면 브라우저 언어를 지원 목록에 매칭해 초기 언어로 사용 (`language.autoDetect: false`로 해제)
- **색약 보정 필터 2종**: 채도 옵션에 적색약·녹색약 보정 추가 — SVG 색행렬 기반, 흰색·회색은 보존하고 문제 색상만 이동
- **페이지 구조 탐색에 랜드마크 탭**: main/nav/aside 등 영역 목록과 위치 이동 (섹셔닝 내부 header/footer, 이름 없는 region은 규격대로 제외). 역할명은 6개 언어의 자연어("본문"·"내비게이션" 등)로 표기
- **색약 보정 필터 데모 페이지**: 색상 표본·상태 표시·차트 범례로 보정 전후를 비교하는 `examples/color-filter.html`
- **장애 유형 프로필 4종 추가** (기존 3종 → 7종): 시각 장애(이미지 대체텍스트 + 포커스 낭독 자동 시작), 고령자(글자·행간·자간 확대 + 커서 강조), 움직임 민감(애니메이션·미디어 정지 + 채도 완화 — 광과민성 발작·전정 장애 대응), 신체 장애(화면 확대 + 커서 강조 + 음성 명령 안내). UI 라벨 6개 언어 지원, 프로필 아이콘 3종 신규 제작
- **프로필 엔진 확장**: 토글형 설정(stopAni·mediaStop·mediaMute)과 동작형 항목(TTS 포커스 낭독 시작, STT 사용 안내 알림)을 프로필에 묶을 수 있게 적용·해제 대칭 구현
- **패널 접근성 보강**: Escape로 패널 닫기(+포커스 복원), 아이콘 모드 라디오 키보드·스크린리더 접근 복원(화살표 이동, "N개 중 X" 낭독), `:focus-visible` 포커스 링, 터치 대상 24px 이상 확대, `prefers-reduced-motion` 존중, aside 랜드마크 이름
- **좁은 화면 대응**: 패널 폭 뷰포트 맞춤(밀어내기 대신 덮기), 아이콘 그리드 2열, `100dvh` 폴백
- **데모 페이지 SEO**: 전 페이지 meta description·canonical·og/twitter 태그, robots.txt·sitemap.xml, Pages 루트를 리다이렉트 대신 실제 랜딩 페이지로 교체
- GitHub Pages 데모 자동 배포 워크플로, 영문 README, 이슈/PR 템플릿, 행동 강령

### 제거
- 호출자 없는 유틸·상수·CSS 규칙 정리 (약 600줄), 복붙 중복 통합(동적 스타일 4종·설정 적용 3중 복제·라디오 동기화 3중 사본)

---

## [2.1.0] - 2026-07-14

### 추가
- **standalone 단일 파일 번들**: `webAccTools.standalone.min.js` — CSS·한국어 로케일·이미지를 인라인하여 파일 1개 복사만으로 폐쇄망에서 동작
- **1줄 설치 지원**: `<script … data-wat-auto>` auto-init, 인라인 config, CSS 자동 주입, 실제 minify 적용
- **배포 zip 패키징**: `npm run package` → `package-build/moduweb-<버전>.zip` (standalone + dist + 설치 가이드 동봉)
- **.env 단일 설정 관리 체계**: 선언적 매핑 테이블 기반 `config.json` 빌드 자동 생성, 비밀키 유입 차단 가드, 값 타입 검증
- **CSS 셀렉터 누수 감사 스크립트** + CI 게이트 (`npm run lint:css`)
- **특성화 테스트 안전망**: 알림·포커스트랩·config 로드 (Phase 0)

### 변경
- **WAT.js 모듈 분해 (Phase 6)**: `IframeStyler`, `Dictionary`(JSONP 보안 개선), `PageStructure`, `TextExtractor`, `PanelBuilder`(개인 옵션 18종 데이터 테이블화), `SettingsApplier`(설정 영속화·프로필 적용 분리), `OverlayManager`(모달 오버레이 정리 일원화) 추출
- 상태·국제화 일원화, 알림 통합, 설정 내보내기/가져오기 추가 (Phase 5)
- Material Icons CDN 의존 제거

### 수정
- 코드 리뷰 발견 사항 전면 수정 — Critical 4건 포함 약 110건
- 접근성 수정 5건 (Phase 1)
- 프로필 설정 토글 스위치 잘림/레이아웃 깨짐 수정

### 제거
- 데드코드 약 1,150줄 — 레거시 TTS 클러스터·미호출 함수·탭 이중화 (Phase 4)

### 문서 (코드-문서 정합성 정정)
- **README API 문서**: 코드에 존재하지 않던 `show()`, `hide()`, `toggle()`, `setLanguage()`, `setTheme()`, `adjustFontSize()`, `toggleHighContrast()`, `toggleColorInvert()` 메서드 문서를 제거하고, 실제 구현 메서드(`changeFontSize`/`changeFontFamily`/`changeColorTheme`/`changeSaturation`/`changeScreenScale`/`changeReadGuide`/`changeTTSSpeed` 등 `change*` 계열, `togglePanel`/`applyProfileSettings`/`resetWatSettings` 등)와 `ttsManager.toggleAutoTTS()`/`toggleFocusTTS()`, `sttManager.toggleVoiceCommand()` 위임 메서드로 교체
- **README 생성자 옵션**: 코드가 읽지 않는 `position`/`theme`/`features` 옵션을 제거하고, 실제 소비 옵션(`configPath`, `language`, `containerID`, `containerTargetSelector`, `containerTargetPosition`, `applySelector`, `excludeSelector`, `styleMode`, `styleCssPath`, `fontFamily`, 비율 옵션들)로 교체
- **README 이벤트**: 실제로 발생하지 않는 `wat:settingsChanged`/`wat:fontSizeChanged`/`wat:stt:stateChanged` 항목 제거 (실제 발생 이벤트는 `wat:initialized` 뿐)
- **ARCHITECTURE.md**: 로케일 목록을 실제 6개(`ko`, `en-US`, `en-GB`, `ja`, `zh`, `de`)로 정정(`en.json` 없음), 존재하지 않는 `assets/js/` 폴더 언급 제거, `config.json` 설명을 실제 구조(`api.dictionary`/`resources.fonts`/`branding`/`settings.ui`)로 정정, `src/` 19개 모듈 레이아웃 섹션 추가(`WAT.js` 약 10,800줄 단일 파일이며 매니저 구조로 분해 진행 중임을 명시)
- **CONTRIBUTING.md**: "빌드 도구 없이 `dist/` 직접 편집" 안내를 실제 워크플로(`src/` 편집 → `npm install`/`npm run build`(Rollup)/`npm test`)로 정정
- **config.example.json**: 코드가 읽지 않는 키(`api.dictionary.retryCount`, `api.dictionary.providers`, `settings.behavior.*`, `settings.accessibility.*`, `settings.ui.autoClose`, `settings.ui.theme`) 제거, `settings.language.supportedLanguages`를 실제 6개 언어로 정정
- **tests/manual/checklist.md**: 전체 테스트 개수 `94` → `84`로 정정

---

## [2.0.1] - 2026-03-16

### 개선
- 빌드 배너·`wat:initialized` 이벤트의 버전 문자열을 `package.json`과 단일화 (Rollup 빌드 시 주입)
- `npm version` 직후 dist가 올바른 버전으로 재생성되도록 스크립트 훅 정리
- `watInit.js`, `dist/watInit.js`, `dist/watInit_ver-manual.js`에서 암묵적 전역 변수(`watOptions`) 선언을 `const`로 수정
- `dist/webAccTools.js`의 `hasOwnProperty` 직접 호출 패턴을 `Object.hasOwn()` / `Object.keys()` 기반으로 교체

### 설정 관리 고도화
- `config.json`, `config.example.json`에 `resources.fonts` 및 `branding` 섹션 추가
- 하드코딩되었던 외부 폰트 URL(Nanum Myeongjo, Noto Serif KR, Material Icons)과 저작권 링크 URL을 `config.json`에서 읽도록 리팩토링
- `_getFallbackConfig()`에 `resources` / `branding` 기본값 추가
- `_applyConfigResources()` 메서드 신규 추가 — config 로드 완료 후 `FONT_FAMILY_OPTIONS` URL을 동적으로 갱신

### 문서
- README에 로컬 개발 환경 설정 가이드 추가 (`config.example.json` → `config.json` 복사 절차 포함)
- README의 `config.json` 예시를 신규 `resources` / `branding` 구조로 업데이트

---

## [2.0.0] - 2025-10

### 추가
- WAT (Web Accessibility Tool) 2.0 초기 릴리즈
- TTS (Text-to-Speech): AutoTTS, FocusTTS, KeyboardTTS 3가지 모드
- STT (Speech-to-Text): 음성 명령어(VoiceCommand) 지원
- 사전 검색 기능 (JSONP 방식, jQuery 의존성 없음)
- 다국어 지원: 한국어, 영어(US/GB), 일본어, 중국어, 독일어
- 색상 조절, 화면 확대, 글꼴 변경, 읽기 지원 등 시각 접근성 기능
- `config.json` 기반 외부 설정 파일 지원
- 중앙집중식 에러 처리 (`ErrorHandler`)
- 옵저버 패턴 기반 상태 관리 (`StateManager`)
- WCAG 2.1 AA / KWCAG 2.1 준수

### 변경
- jQuery 의존성 완전 제거, 순수 Vanilla JavaScript로 전환

---

[Unreleased]: https://github.com/Daegu-Cyber-University/ModuWeb/compare/v2.1.0...HEAD
[2.1.0]: https://github.com/Daegu-Cyber-University/ModuWeb/compare/v2.0.1...v2.1.0
[2.0.1]: https://github.com/Daegu-Cyber-University/ModuWeb/compare/v2.0.0...v2.0.1
[2.0.0]: https://github.com/Daegu-Cyber-University/ModuWeb/releases/tag/v2.0.0
