ACTUAL CODEX CLI RUN / STEP 06
Codex CLI 0.153.4 · captured 11 September 2026

This is a selected event transcript, not the Codex Desktop UI.
Reasoning, environment diagnostics and supporting skill instructions are omitted. Paths are shortened.

COMMAND
codex exec -C <workspace> --sandbox workspace-write --json --output-last-message 06-final.txt - < prompts/06-handoff.txt

PROMPT SENT
อ่าน inputs.md, implementation-decisions.md, browser-verification.json, brief.md, evidence.csv และ source ที่มี
รอบนี้ห้ามแก้ index.html/style.css/main.js และห้ามรัน server/deploy/modelอื่น
แก้ brief.md และ evidence.csv ให้สะท้อนข้อกำหนดที่ได้รับเพิ่มจริง:
- Day1 บท00–05 และDay2บท06–10 ยืนยันแล้วจาก dayData ของโครงการ
- มี theme toggle Light/Dark ยืนยันแล้วใน prompt04; Lightเป็นdefaultและเก็บเฉพาะตัวเลือกของผู้ใช้
- CTAรองดูบทเรียนทั้งหมดไป #lessons ยืนยันในprompt02 ไม่ใช่ปลายทาง / ที่ยังสงสัยในbriefแรก
บันทึกแหล่งการยืนยันและการเปลี่ยนสถานะ GAP โดยไม่ลบประวัติรอบแรก (snapshotเดิมเก็บแยกแล้ว)
อย่าอ้างว่าข้อมูลผู้สอน หน่วยกิต เกณฑ์คะแนน หรือLMSได้รับการยืนยันแล้ว
สร้าง handoff.md ที่สรุปไฟล์/CTA/interaction/token/หลักฐานตรวจ/สิ่งที่ยังไม่ทำ
อ่านผล browser ที่แนบแล้วรายงานว่า parent runner เป็นผู้ทดสอบ ไม่อ้างว่าคุณรัน browser เอง
เกณฑ์ที่ผ่านคือเฉพาะในรายงาน; ยังไม่อ้างเผยแพร่ public จนมีหลักฐานจากขั้นdeploy
อธิบายสั้นๆ ว่าเมื่อข้อกำหนดได้รับคำตอบแล้ว ต้องแก้ทั้ง brief/evidence และimplementationให้ตรงกัน


EXECUTED COMMAND
/bin/bash -lc "pwd && rg --files -g 'inputs.md' -g 'implementation-decisions.md' -g 'browser-verification.json' -g 'brief.md' -g 'evidence.csv' -g 'index.html' -g 'style.css' -g 'main.js' -g 'AGENTS.md' -g '"'!node_modules'"'"
OUTPUT
<workspace>
brief.md
inputs.md
main.js
style.css
index.html
implementation-decisions.md
browser-verification.json
evidence.csv

EXIT 0

EXECUTED COMMAND
/bin/bash -lc "sed -n '1,260p' inputs.md && sed -n '1,320p' implementation-decisions.md && sed -n '1,320p' browser-verification.json && sed -n '1,360p' brief.md && sed -n '1,360p' evidence.csv && rg -n -i -C 3 'dayData|theme|dark|light|#lessons|cta|localStorage|prompt0[234]|credit|instructor|LMS|grade|คะแนน|ผู้สอน|หน่วยกิต' index.html style.css main.js"
OUTPUT
# ข้อมูลตั้งต้นสำหรับเว็บไซต์ตัวอย่างรายวิชา

S1 — ข้อมูลที่ผู้ใช้ให้: 977-121 Module: Website Design and Development, มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต / Prince of Songkla University, Phuket Campus.
S2 — design-system/course.json และ docs/instructor/course-guide.md ของหลักสูตรนี้: AI Web Studio — ออกแบบและพัฒนาเว็บไซต์ด้วย AI เป็นหน่วย workshop 2 วัน × 4 ชั่วโมง = 8 ชั่วโมง รวมพัก 10 นาทีต่อวัน เป็นส่วนหนึ่งของรายวิชา ไม่ใช่ชั่วโมง/หน่วยกิต/ประมวลรายวิชาฉบับมหาวิทยาลัยทั้งหมด
S3 — DESIGN.md และ Rawinnipa Brand Guidelines v1.0 ที่ใช้กับ course shell: Inter + Noto Sans Thai, light default: #F7F7F7 พื้น, #0A0A0A ข้อความ, #3EDC81 accent มีข้อความเข้ม, #17653F สำหรับข้อความเขียวบนพื้นอ่อน. Dark: #0A0A0A canvas, #171717 surface, #F7F7F7 text. จำกัด green เป็นจุดเน้น; focus มองเห็น; print กระดาษขาว. ลิงก์ผู้ออกแบบ/ผู้จัดทำสื่อ https://rawinsoft.com/ ไม่อ้าง partnership หรือเจ้าของมหาวิทยาลัยเพิ่ม. ห้ามสร้างตราหรือโลโก้มหาวิทยาลัยขึ้นเอง
S4 — บทเรียนที่มีจริงใน repository (ชื่อย่อใช้แสดงได้):
- 00 | บทเรียน 00 — เตรียมเครื่องและเข้าใจว่าเว็บทำงานอย่างไร | /learn/lessons/00-setup-and-web-basics/
- 01 | บทที่ 1: พื้นฐาน Vibe Coding สำหรับเว็บที่ส่งมอบได้จริง | /learn/lessons/01-vibe-coding-foundations/
- 02 | บทที่ 2: Agent Skills, MCP และ Plugins โดยไม่ทำให้บริบทพัง | /learn/lessons/02-agent-skills/
- 03 | บทที่ 3: Specs และ Prompts สำหรับเว็บบริษัท, Catalog และเว็บ animation | /learn/lessons/03-specs-and-prompts/
- 04 | บทเรียน 04 — ออกแบบ, ภาพ และคุณภาพก่อนเขียนหน้าเว็บ | /learn/lessons/04-design-and-assets/
- 05 | บทเรียน 05 — เว็บบริษัท: contact form ที่รันกับ demo นี้ได้จริง | /learn/lessons/05-company-website/
- 06 | บทเรียน 06 — เว็บเช่าอุปกรณ์: availability และ capacity ของ demo ที่รันได้จริง | /learn/lessons/06-rental-and-data/
- 07 | บทเรียน 07 — GSAP product story, storefront และ quote demo | /learn/lessons/07-gsap-storefront/
- 08 | บทเรียน 08 — รันและตรวจ deployment path ของโปรเจกต์ Cloudflare นี้ | /learn/lessons/08-cloudflare-deploy/
- 09 | บทเรียน 09 — Production Operations: security, observability, rollback และต้นทุน | /learn/lessons/09-production-operations/
- 10 | บทเรียน 10 — สร้างเว็บของตนเองและส่งมอบอย่างตรวจสอบได้ | /learn/lessons/10-capstone-and-handoff/

S5 — ปลายทางที่มีจริง: / (เว็บไซต์สื่อหลักสูตร), /resources/, /handbook/, /learn/labs/install-ai-tools/, /learn/labs/research-to-brand-website/, /learn/labs/design-tools-and-mcp/. เว็บไซต์ตัวอย่างจะอยู่ /examples/course-website/. ลิงก์อ่านการสร้างทีละขั้นใช้ /learn/labs/build-course-website-step-by-step/ (กำลังสร้าง)
S6 — สินทรัพย์ font ที่ใช้ได้: /fonts/Inter-Regular.woff2, /fonts/Inter-Bold.woff2, /fonts/NotoSansThai-Regular.woff2, /fonts/NotoSansThai-Bold.woff2. ใช้ตัวอักษร/HTML/SVG ธรรมดา ไม่ต้องสร้างภาพ raster หรือโหลด font ภายนอก

GAP — ยังไม่มีเจ้าของยืนยันชื่อผู้สอน จำนวนหน่วยกิต ตารางภาคเรียน เกณฑ์ให้คะแนน ช่องทางสมัคร หรือบัญชี LMS. ไม่สร้างข้อมูลเหล่านี้ ไม่สร้าง login/รับสมัครที่ทำงานปลอม
PROPOSAL — กลุ่มเป้าหมายของ prototype คือผู้เรียนที่ต้องการรู้ว่าเริ่มตรงไหน เลือกบทเรียน และดูแผน workshop. เว็บไซต์นี้เป็นตัวอย่างประกอบการเรียน ไม่ใช่ระบบมหาวิทยาลัยอย่างเป็นทางการ

ขอบเขตงาน
- เว็บภาษาไทย static HTML/CSS/JS หน้าเดียว; API/ฐานข้อมูลไม่จำเป็นสำหรับเนื้อหาสาธารณะ
- ให้ไปถึงบทเรียนได้จริง; optional ค้นหาบทเรียนและกรอง Day1/Day2/ทั้งหมด
- โปรเจ็กต์เดิมมีเวลา workshop 8h; เนื้อหาเกินเวลาเป็นอ่านต่อ. แสดง Day1/Day2 สรุปไม่แต่งตารางรายวิชาเต็ม
- สร้างแบบทีละขั้น: brief → semantic HTML → responsive CSS → JS interaction → QA → publication
- code ทั้งหมดและผลแต่ละช่วงต้องตรวจ/ย้อนดูได้

ข้อมูลยืนยันเพิ่มเติมหลังทบทวน brief (ก่อนขั้น02): แบ่ง Day1 เป็นบท00–05, Day2 เป็นบท06–10 ตาม dayData ใน scripts/build.mjs. การแบ่งนี้เป็นเส้นทางคลังบทเรียน; ตารางในห้องยังเลือกกิจกรรมตามเวลา4ชม/วัน ไม่ได้หมายถึงต้องทำครบทุกเนื้อหา
แหล่งอ้างอิงชื่อรายวิชาภายนอก: https://computing.psu.ac.th/th/b-eng-digital-engineer-international-program/ ตรวจ11กันยายน2026. ใช้เฉพาะยืนยันชื่อวิชา/บริบทPSUPhuket; ไม่เอาจำนวนหน่วยกิตในแผนคนละรุ่นมาใส่เป็นเวลาworkshop
# ข้อกำหนดเพิ่มเติมที่ส่งจริงระหว่างการสร้าง

D1 — Prompt02: Day1 บท00–05, Day2บท06–10 ยึด scripts/build.mjs dayData. ช่วงเนื้อหานี้ไม่เปลี่ยน8hworkshopและพักวันละ10นาที
D2 — Prompt02: CTAรองไป #lessons, CTAหลักไปบท00จริง /learn/lessons/00-setup-and-web-basics/, คู่มือไป/handbook/หรือ/resources/
D3 — Prompt04: เพิ่มtheme toggle, lightdefaultแม้OSdark, dark/lightstoragekeypsu-course-website-theme-v1, storageerrorfallback, search/dayfilter/status/empty/resetและnoJSfallback

ทั้งสามข้อเป็นคำสั่งและข้อมูลที่ parent ให้จริง ไม่มีการอนุมัติจากมหาวิทยาลัยหรือเจ้าของวิชาเต็มเพิ่มเติม
{
  "source": "Parent-run Playwright suite, not a test executed by this child Codex run",
  "command": "npx playwright test tests/course-website.spec.mjs --reporter=json",
  "baseURL": "http://127.0.0.1:3320",
  "stats": {
    "startTime": "2026-09-11T05:25:36.622Z",
    "duration": 13749.389,
    "expected": 5,
    "skipped": 0,
    "unexpected": 0,
    "flaky": 0
  },
  "tests": [
    {
      "title": "course website presents the complete two-day 977-121 workshop path",
      "status": "expected"
    },
    {
      "title": "lesson search and day filters combine, report results, and reset safely",
      "status": "expected"
    },
    {
      "title": "theme changes only after an explicit choice and survives storage failures",
      "status": "expected"
    },
    {
      "title": "course content and lesson links remain available without JavaScript",
      "status": "expected"
    },
    {
      "title": "course shell is keyboard accessible and fits target viewports in both themes",
      "status": "expected"
    }
  ],
  "scope": [
    "11 lessons and day mapping",
    "search/filter/empty/reset including hostile query",
    "defaultLight OSdark + dark persistence + blocked storage",
    "noJS links available controls hidden",
    "keyboard skip and 320/390/1440 Light/Dark nooverflow + axe serious/critical0"
  ],
  "publication": "not yet tested in public"
}
# Brief — เว็บไซต์ตัวอย่างรายวิชา 977-121

## กรอบงานและสถานะข้อมูล

- **ขอบเขตผลลัพธ์:** เอกสารสังเคราะห์สำหรับหน้า static HTML/CSS/JS ภาษาไทยหน้าเดียวในอนาคต; เอกสารนี้ไม่ใช่หน้าเว็บ และไม่มีการทำ web research
- **สถานะ:** Draft สำหรับให้เจ้าของตรวจสอบก่อนเข้าสู่ semantic HTML
- **ตำแหน่งผลิตภัณฑ์:** เว็บไซต์ตัวอย่างประกอบการเรียนที่ `/examples/course-website/` ไม่ใช่ระบบมหาวิทยาลัยอย่างเป็นทางการ
- **ข้อจำกัด:** ไม่สร้างตรา/โลโก้มหาวิทยาลัย ข้อมูลผู้สอน หน่วยกิต ตารางภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร บัญชี LMS หรือ login/รับสมัครจำลอง

## FACT

- ชื่อรายวิชา: **977-121 Module: Website Design and Development**
- สถาบันที่ระบุ: **มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต / Prince of Songkla University, Phuket Campus**
- **AI Web Studio — ออกแบบและพัฒนาเว็บไซต์ด้วย AI** เป็น workshop ภายในรายวิชา ระยะเวลา 2 วัน × 4 ชั่วโมง (รวม 8 ชั่วโมง) และมีพัก 10 นาทีต่อวัน; ไม่ใช่ชั่วโมง หน่วยกิต หรือประมวลรายวิชาฉบับเต็มของมหาวิทยาลัย
- มีบทเรียนจริง 11 บท (00–10) และมีปลายทางบทเรียน/ทรัพยากรตาม content inventory ด้านล่าง
- visual system ที่มีอยู่ใช้ Inter + Noto Sans Thai, light เป็นค่าเริ่มต้น และใช้สีเขียวอย่างจำกัดเพื่อเน้น

## INFERENCE

- ผู้เข้าชมหลักต้องการตอบคำถามเร็ว ๆ ว่า “เริ่มตรงไหน”, “มีบทเรียนใดบ้าง” และ “workshop สองวันนี้ทำอะไร”; ดังนั้นหน้าเดียวควรให้ทางเลือกเริ่มเรียนและแผน Day 1/Day 2 อยู่ก่อนเนื้อหารายละเอียด
- CTA ควรพาไปยังปลายทางที่มีอยู่จริงเท่านั้น และป้ายกำกับต้องบอกชนิด/สถานะของปลายทางอย่างตรงไปตรงมา โดยเฉพาะลิงก์บทความแบบทีละขั้นที่ยังอยู่ระหว่างสร้าง
- เนื่องจาก workshop เป็นเพียงส่วนหนึ่งของ module จึงควรนำเสนอเป็น “แผน workshop” ไม่ใช่ตารางสอนหรือคำอธิบายรายวิชาฉบับสมบูรณ์

## PROPOSAL

### เป้าหมายและ audience

**เป้าหมายหลัก:** ช่วยผู้เรียนค้นพบเส้นทางเริ่มเรียน เข้าถึงบทเรียนจริง และเข้าใจขอบเขตของ AI Web Studio workshop โดยไม่ทำให้เข้าใจว่าเป็นเว็บไซต์ทางการหรือระบบรับสมัคร

**Audience หลัก:** ผู้เรียนที่ต้องการเริ่มทำเว็บไซต์ด้วย AI และต้องเลือกบทเรียน/ดูภาพรวม workshop ก่อนเข้าเนื้อหา

**Audience รอง:** ผู้สอนหรือผู้ทบทวนสื่อที่ต้องการตรวจรายการบทเรียนและปลายทางของหลักสูตรอย่างรวดเร็ว

### ข้อเสนอคุณค่า (value proposition)

“เส้นทางเรียนรู้เพื่อออกแบบและพัฒนาเว็บไซต์ด้วย AI: เริ่มจากเครื่องมือและพื้นฐาน ไปจนถึงการส่งมอบที่ตรวจสอบได้ พร้อม workshop สองวันเป็นส่วนหนึ่งของ module.”

### CTA และปลายทาง

| ระดับ | ป้าย CTA ที่เสนอ | ปลายทาง | หมายเหตุ |
| --- | --- | --- | --- |
| หลัก | `เริ่มจากบทเรียน 00` | `/learn/lessons/00-setup-and-web-basics/` | เริ่มต้นที่จุดเข้าเรียนชัดเจน |
| รอง | `ดูบทเรียนทั้งหมด` | `/` | ใช้เมื่อหน้าเว็บไซต์สื่อหลักสูตรแสดงรายการเรียน; ยืนยัน label ใน implementation อีกครั้ง |
| รอง | `ดูแผน AI Web Studio 2 วัน` | anchor `#workshop` | เลื่อนภายในหน้า ไม่อ้างว่าเป็นตารางรายวิชาเต็ม |
| รอง | `เปิดคู่มือการเรียน` | `/handbook/` | ปลายทางที่มีจริง |
| รอง | `ดูทรัพยากร` | `/resources/` | ปลายทางที่มีจริง |
| บริบท | `อ่านการสร้างทีละขั้น` | `/learn/labs/build-course-website-step-by-step/` | ติดป้าย “กำลังสร้าง” จนกว่าจะยืนยันว่าเผยแพร่แล้ว |
| เครดิต | `Rawinnipa` | `https://rawinsoft.com/` | ลิงก์ผู้ออกแบบ/ผู้จัดทำสื่อเท่านั้น ไม่อ้าง partnership หรือเจ้าของมหาวิทยาลัย |

### ลำดับ section ของหน้าเดียว

1. **Utility/header** — ชื่อรายวิชา, สถาบัน, ป้าย “เว็บไซต์ตัวอย่างประกอบการเรียน”, การข้ามไปเนื้อหาหลัก (skip link), สวิตช์ theme
2. **Hero** — ชื่อรายวิชาเต็ม, ชื่อ workshop, value proposition, CTA หลัก และ CTA ดู workshop
3. **ขอบเขต AI Web Studio** — ข้อความชัดเจนว่าเป็นส่วนหนึ่งของ module; 2 วัน × 4 ชั่วโมง, พัก 10 นาที/วัน, รวม 8 ชั่วโมง; ไม่แทนรายละเอียดรายวิชาฉบับมหาวิทยาลัย
4. **แผน workshop Day 1 / Day 2** — สรุปกิจกรรมตามระดับหัวข้อเท่านั้น; ไม่ประดิษฐ์ตารางเวลาเต็มหรือผลการประเมิน
5. **เส้นทางบทเรียน** — รายการ 00–10 พร้อมชื่อและลิงก์ที่มีจริง; search/filter แบบ optional: ทั้งหมด, Day 1, Day 2 โดยต้องประกาศเกณฑ์การจัดกลุ่มก่อนใช้
6. **Labs และแหล่งเรียนต่อ** — ลิงก์ labs ที่มีจริง, handbook และ resources; ลิงก์ “อ่านการสร้างทีละขั้น” พร้อมป้าย “กำลังสร้าง”
7. **ข้อจำกัด/ความโปร่งใส** — ย้ำสถานะเว็บไซต์ตัวอย่าง; ไม่มี login, รับสมัคร, LMS หรือข้อมูลทางวิชาการที่ยังไม่ยืนยัน
8. **Footer** — ชื่อรายวิชาและ PSU Phuket เป็นข้อความ, ลิงก์ Rawinnipa ตามขอบเขตเครดิต; ไม่มีตราหรือโลโก้ที่สร้างขึ้น

### Content inventory

| กลุ่ม | เนื้อหาที่แสดง | ปลายทาง |
| --- | --- | --- |
| รายวิชา | 977-121 Module: Website Design and Development; มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต / Prince of Songkla University, Phuket Campus | ไม่มีลิงก์สถาบันที่ยืนยัน |
| Workshop | AI Web Studio — ออกแบบและพัฒนาเว็บไซต์ด้วย AI; 2 วัน × 4 ชั่วโมง = 8 ชั่วโมง; พัก 10 นาที/วัน | `#workshop` |
| บทเรียน 00 | เตรียมเครื่องและเข้าใจว่าเว็บทำงานอย่างไร | `/learn/lessons/00-setup-and-web-basics/` |
| บทเรียน 01 | พื้นฐาน Vibe Coding สำหรับเว็บที่ส่งมอบได้จริง | `/learn/lessons/01-vibe-coding-foundations/` |
| บทเรียน 02 | Agent Skills, MCP และ Plugins โดยไม่ทำให้บริบทพัง | `/learn/lessons/02-agent-skills/` |
| บทเรียน 03 | Specs และ Prompts สำหรับเว็บบริษัท, Catalog และเว็บ animation | `/learn/lessons/03-specs-and-prompts/` |
| บทเรียน 04 | ออกแบบ, ภาพ และคุณภาพก่อนเขียนหน้าเว็บ | `/learn/lessons/04-design-and-assets/` |
| บทเรียน 05 | เว็บบริษัท: contact form ที่รันกับ demo นี้ได้จริง | `/learn/lessons/05-company-website/` |
| บทเรียน 06 | เว็บเช่าอุปกรณ์: availability และ capacity ของ demo ที่รันได้จริง | `/learn/lessons/06-rental-and-data/` |
| บทเรียน 07 | GSAP product story, storefront และ quote demo | `/learn/lessons/07-gsap-storefront/` |
| บทเรียน 08 | รันและตรวจ deployment path ของโปรเจกต์ Cloudflare นี้ | `/learn/lessons/08-cloudflare-deploy/` |
| บทเรียน 09 | Production Operations: security, observability, rollback และต้นทุน | `/learn/lessons/09-production-operations/` |
| บทเรียน 10 | สร้างเว็บของตนเองและส่งมอบอย่างตรวจสอบได้ | `/learn/lessons/10-capstone-and-handoff/` |
| Labs/ทรัพยากร | install AI tools; research-to-brand website; design tools and MCP; resources; handbook | `/learn/labs/install-ai-tools/`; `/learn/labs/research-to-brand-website/`; `/learn/labs/design-tools-and-mcp/`; `/resources/`; `/handbook/` |

### States

| State | ข้อเสนอพฤติกรรม/ข้อความ |
| --- | --- |
| Default | แสดง hero, CTA, workshop summary และรายการบทเรียนทั้งหมด |
| Light (default) | พื้น `#F7F7F7`, ข้อความ `#0A0A0A`, accent `#3EDC81` พร้อมข้อความเข้ม, ข้อความเขียวบนพื้นอ่อน `#17653F` |
| Dark | canvas `#0A0A0A`, surface `#171717`, ข้อความ `#F7F7F7`; รักษา contrast และไม่ใช้เขียวเป็นข้อความหลักบนพื้นมืดหากยังไม่ตรวจ contrast |
| Theme preference | ใช้ light เป็น default; หากมีสวิตช์ ต้องมองเห็นสถานะและทำงานด้วยคีย์บอร์ด |
| Lesson filter/search (optional) | แสดงผล “ไม่พบบทเรียนที่ตรงกัน” พร้อมปุ่ม/ลิงก์คืนค่า; filter Day 1/Day 2 ใช้ได้ต่อเมื่อเจ้าของยืนยัน mapping |
| CTA pending | `อ่านการสร้างทีละขั้น` มีป้าย “กำลังสร้าง” และไม่อ้างว่าอ่านได้แล้ว |
| Link failure/unknown | ไม่สร้างหน้า 404 หรือ loading simulation; ใช้เฉพาะปลายทางที่ S5 ระบุ |
| Print | พื้นกระดาษขาว, ข้อความอ่านได้, ไม่พึ่งสีอย่างเดียวเพื่อสื่อความหมาย |

### Responsive

- **Mobile ก่อน:** หนึ่งคอลัมน์, CTA กว้างแตะง่าย, nav ไม่บังคับเลื่อนแนวนอน, lesson cards เรียงแนวตั้ง
- **Tablet:** hero และ workshop สามารถจัดสองคอลัมน์เมื่อยังเหลือพื้นที่อ่านง่าย; filters อยู่ก่อนรายการผลลัพธ์
- **Desktop:** ใช้ความกว้างข้อความจำกัดเพื่อการอ่าน, lesson grid หลายคอลัมน์ตามพื้นที่, header ยังเข้าถึง CTA หลักได้
- ทุกขนาด: ไม่ซ่อนเนื้อหาสำคัญเพียงเพราะ viewport, รองรับ text zoom/reflow, และไม่ยึดความหมายด้วย hover เพียงอย่างเดียว

### Accessibility acceptance checks

- [ ] ใช้ semantic landmarks (`header`, `nav`, `main`, `section`, `footer`) และลำดับ heading ไม่ข้ามระดับ
- [ ] มี skip link; ทุก CTA/ลิงก์เข้าถึงด้วยคีย์บอร์ด และ focus ชัดเจน
- [ ] สี light/dark และทุกสถานะ focus/hover/selected ผ่าน contrast ที่เหมาะสม; สีเขียวไม่ใช่ตัวบอกความหมายเพียงอย่างเดียว
- [ ] สวิตช์ theme และ filter/search (หากสร้าง) มี accessible name, state และประกาศการเปลี่ยนแปลงผลลัพธ์อย่างเหมาะสม
- [ ] ข้อความไทยใช้ Noto Sans Thai และข้อความ Latin ใช้ Inter จาก font ในระบบ; ไม่มี external font
- [ ] ขนาดเป้าหมายสัมผัสเพียงพอ, หน้า reflow ได้ที่ความกว้างแคบ/zoom, และไม่มี horizontal overflow โดยไม่จำเป็น
- [ ] ไม่มีภาพที่ต้องพึ่งพาเพื่อเข้าใจเนื้อหา; ถ้ามี SVG ตกแต่งต้องซ่อนจาก assistive technology
- [ ] โครงสร้าง print เป็นพื้นขาวและยังอ่านลิงก์/ป้าย “กำลังสร้าง” ได้

## ทางเลือกภาพ (ไม่สร้าง raster/ตรามหาวิทยาลัย)

### ทางเลือก A — Type-led learning map

ใช้ typography เป็นภาพหลัก: หมายเลขบทเรียน 00–10 ขนาดใหญ่, เส้นทาง/จุดสถานะด้วย CSS หรือ SVG ธรรมดา, และ chip “Day 1/Day 2”. ภาพสื่อการเดินทางผ่านเนื้อหาโดยไม่ต้องใช้รูปถ่ายหรือสินทรัพย์ใหม่; ใช้ green เฉพาะจุดเริ่มต้น, CTA และสถานะที่ได้รับการยืนยัน.

### ทางเลือก B — Editorial workshop cards

ใช้การ์ดขาว/ผิว dark ที่มีตัวเลข “Day 1”, “Day 2” และ glyph จาก HTML/SVG ธรรมดา (เช่น cursor, bracket, check) พร้อมภาพพิมพ์ขนาดใหญ่. ให้บรรยากาศ workshop ชัด แต่ต้องระวังไม่ทำให้ผู้ใช้เข้าใจว่าบัตรเหล่านี้คือกำหนดการรายวิชาทางการ.

### Draft ที่เลือก — ทางเลือก A

เลือก **Type-led learning map** เพราะสอดคล้องกับแบรนด์เดิมที่เรียบ ใช้สีเขียวจำกัด และให้บทเรียนจริงเป็นศูนย์กลาง. ลดความเสี่ยงการสร้างภาพ/ตรามหาวิทยาลัยหรือการใส่บริบท workshop เกินข้อเท็จจริง. จะใช้เฉพาะข้อความ, HTML และ SVG ธรรมดาตามสินทรัพย์ที่อนุญาต.

## GAP — ต้องถามเจ้าของก่อน implementation

1. ต้องการให้ชื่อไทยของรายวิชามีหรือไม่? ปัจจุบันยืนยันเพียงชื่อ `977-121 Module: Website Design and Development`.
2. Mapping ที่ได้รับอนุมัติของบทเรียนใดอยู่ Day 1 และ Day 2 คืออะไร? จนกว่าจะยืนยัน ต้องไม่เปิด filter Day 1/Day 2 หรือใส่ป้ายรายบท.
3. CTA `ดูบทเรียนทั้งหมด` ควรชี้ไปหน้าใด/anchor ใด? S5 ยืนยันเพียง `/` เป็นเว็บไซต์สื่อหลักสูตร ไม่ได้ยืนยันส่วนรายการบทเรียน.
4. ปลายทาง `/learn/labs/build-course-website-step-by-step/` เผยแพร่เมื่อใด? ก่อนนั้นต้องคงป้าย “กำลังสร้าง” หรือซ่อน CTA.
5. อนุมัติข้อความ disclaimer ว่า “เว็บไซต์ตัวอย่างประกอบการเรียน ไม่ใช่ระบบมหาวิทยาลัยอย่างเป็นทางการ” หรือมีถ้อยคำที่เจ้าของกำหนดหรือไม่?
6. ผู้ใช้ต้องการ theme toggle จริงหรือเพียงรองรับ system preference? ข้อกำหนด design system ระบุ light default และ dark palette แต่ยังไม่ยืนยัน interaction.
7. ยืนยันว่าต้องการแสดงลิงก์ Rawinnipa ใน footer หรือไม่; หากแสดงให้ใช้เพียงเครดิตผู้ออกแบบ/ผู้จัดทำสื่อ.
8. ผู้สอน หน่วยกิต ภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร และ LMS จะได้รับอนุมัติให้แสดงหรือไม่? ถ้าไม่ ต้องคงไม่แสดงทั้งหมด.

source_id,classification,claim,evidence,brief_use
S1,FACT,"ชื่อรายวิชาและสถาบัน","977-121 Module: Website Design and Development; มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต / Prince of Songkla University, Phuket Campus","ชื่อใน header/hero/footer และการระบุสถาบันเป็นข้อความ"
S2,FACT,"AI Web Studio เป็น workshop 2 วัน x 4 ชั่วโมง รวม 8 ชั่วโมง พัก 10 นาทีต่อวัน และเป็นส่วนหนึ่งของรายวิชา","design-system/course.json และ docs/instructor/course-guide.md ตามข้อมูลตั้งต้น; ไม่ใช่ชั่วโมง หน่วยกิต หรือประมวลรายวิชาฉบับมหาวิทยาลัยทั้งหมด","section ขอบเขตและสรุป workshop; ห้ามทำตารางรายวิชาเต็มหรืออ้างหน่วยกิต"
S3,FACT,"course shell ใช้ Inter และ Noto Sans Thai; light/dark palette และข้อจำกัดแบรนด์","DESIGN.md และ Rawinnipa Brand Guidelines v1.0 ตามข้อมูลตั้งต้น: light #F7F7F7/#0A0A0A/#3EDC81/#17653F; dark #0A0A0A/#171717/#F7F7F7; green จำกัด; visible focus; print white; rawinsoft.com เป็นเครดิตเท่านั้น; ห้ามสร้างตรา/โลโก้มหาวิทยาลัย","states, responsive/accessibility, visual direction และ footer"
S4,FACT,"มีบทเรียนจริง 11 บท 00-10 พร้อมชื่อและ URL","รายการบทเรียนและเส้นทาง /learn/lessons/00-setup-and-web-basics/ ถึง /learn/lessons/10-capstone-and-handoff/ ที่ให้มา","content inventory และ lesson-path section"
S5,FACT,"มีปลายทางหลัก resources handbook labs example และบทความทีละขั้นกำลังสร้าง","/; /resources/; /handbook/; labs 3 แห่ง; /examples/course-website/; /learn/labs/build-course-website-step-by-step/ กำลังสร้าง","CTA และการติดป้าย pending"
S6,FACT,"ใช้ไฟล์ font ภายในและ HTML/SVG ธรรมดาโดยไม่ต้องสร้าง raster หรือโหลด font ภายนอก","/fonts/Inter-Regular.woff2; /fonts/Inter-Bold.woff2; /fonts/NotoSansThai-Regular.woff2; /fonts/NotoSansThai-Bold.woff2","ข้อเสนอภาพ, typography และ accessibility"
S1-S6,INFERENCE,"ผู้เรียนต้องการจุดเริ่ม เลือกบทเรียน และดูภาพรวม workshop ก่อนรายละเอียด","อนุมานจากข้อเสนอ prototype ในข้อมูลตั้งต้น ร่วมกับรายการบทเรียนและข้อจำกัด workshop","จัด hero, CTA เริ่มจากบทเรียน 00, workshop ก่อน lesson index"
S2-S5,INFERENCE,"Day 1/Day 2 filter ต้องไม่เปิดจนกว่าจะมี mapping รายบทที่ยืนยัน","มีเพียงการยืนยันว่า workshop 2 วัน แต่ไม่มีการจัดบทเรียนลงวัน","GAP และ state ของ filter"
S3,GAP,"theme toggle เป็น interaction ที่เป็นไปได้แต่ยังไม่ยืนยัน","ข้อมูลกำหนด light default และ dark palette แต่ไม่ระบุว่าต้องมีสวิตช์","เสนอเป็น state/คำถามยืนยัน ไม่ใช่ข้อกำหนดที่ยืนยันแล้ว"
S5,GAP,"CTA ดูบทเรียนทั้งหมดชี้ / ได้ชั่วคราวแต่ต้องยืนยัน anchor/เนื้อหาปลายทาง","S5 ระบุ / เป็นเว็บไซต์สื่อหลักสูตร แต่ไม่ยืนยันว่าเป็น lesson index โดยตรง","GAP ก่อน implementation"
S1-S6,PROPOSAL,"เลือกภาพ Type-led learning map เป็น draft","ใช้ typography หมายเลขบทเรียน เส้นทาง CSS/SVG และ green แบบจำกัด; ไม่ใช้ raster หรือตรามหาวิทยาลัย","visual direction draft"
S1-S6,GAP,"ห้ามสร้างข้อมูลผู้สอน หน่วยกิต ภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร หรือ LMS","GAP ที่ระบุในข้อมูลตั้งต้น","ตัดออกจากหน้าและรวบรวมคำถามเจ้าของ"
main.js-1-(() => {
main.js-2-  "use strict";
main.js-3-
main.js:4:  const storageKey = "psu-course-website-theme-v1";
main.js-5-  const root = document.documentElement;
main.js:6:  const themeToggle = document.querySelector("#theme-toggle");
main.js-7-  const controls = document.querySelector(".lesson-controls");
main.js-8-  const search = document.querySelector("#lesson-search");
main.js-9-  const filterButtons = [...document.querySelectorAll("[data-filter]")];
--
main.js-13-  const lessons = [...document.querySelectorAll("article[data-lesson][data-day]")];
main.js-14-  const lessonDays = [...document.querySelectorAll(".lesson-day")];
main.js-15-
main.js:16:  let theme = "light";
main.js-17-  let selectedFilter = "all";
main.js-18-
main.js-19-  try {
main.js:20:    const savedTheme = window.localStorage.getItem(storageKey);
main.js:21:    if (savedTheme === "light" || savedTheme === "dark") {
main.js:22:      theme = savedTheme;
main.js-23-    }
main.js-24-  } catch (_) {
main.js:25:    // Theme selection still works for this visit when storage is unavailable.
main.js-26-  }
main.js-27-
main.js:28:  function setTheme(nextTheme) {
main.js:29:    theme = nextTheme;
main.js:30:    root.dataset.theme = theme;
main.js:31:    const isDark = theme === "dark";
main.js:32:    themeToggle.setAttribute("aria-pressed", String(isDark));
main.js:33:    themeToggle.textContent = isDark ? "เปลี่ยนเป็นโหมดสว่าง" : "เปลี่ยนเป็นโหมดมืด";
main.js:34:    themeToggle.setAttribute(
main.js-35-      "aria-label",
main.js:36:      isDark
main.js-37-        ? "โหมดปัจจุบัน: มืด เปลี่ยนเป็นโหมดสว่าง"
main.js-38-        : "โหมดปัจจุบัน: สว่าง เปลี่ยนเป็นโหมดมืด"
main.js-39-    );
--
main.js-76-    updateLessons();
main.js-77-  }
main.js-78-
main.js:79:  if (themeToggle) {
main.js:80:    themeToggle.hidden = false;
main.js:81:    setTheme(theme);
main.js:82:    themeToggle.addEventListener("click", () => {
main.js:83:      const nextTheme = theme === "dark" ? "light" : "dark";
main.js:84:      setTheme(nextTheme);
main.js-85-      try {
main.js:86:        window.localStorage.setItem(storageKey, nextTheme);
main.js-87-      } catch (_) {
main.js-88-        // Storage can be disabled without preventing the visual toggle.
main.js-89-      }
--
style.css-31-}
style.css-32-
style.css-33-:root {
style.css:34:  color-scheme: light;
style.css-35-  --surface: #f7f7f7;
style.css-36-  --surface-raised: #ffffff;
style.css-37-  --text: #0a0a0a;
--
style.css-45-  --page-width: 72rem;
style.css-46-}
style.css-47-
style.css:48:html[data-theme="dark"] {
style.css:49:  color-scheme: dark;
style.css-50-  --surface: #0a0a0a;
style.css-51-  --surface-raised: #171717;
style.css-52-  --text: #f7f7f7;
--
style.css-137-button, select { padding-inline: 0.8rem; }
style.css-138-input, textarea { width: 100%; padding: 0.6rem 0.8rem; }
style.css-139-
style.css:140:.theme-toggle { white-space: nowrap; }
style.css-141-.lesson-controls { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 1rem; align-items: end; margin-top: 1.5rem; padding: 1rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-raised); }
style.css-142-.lesson-search-field { min-width: 0; }
style.css-143-.lesson-search-field label, .lesson-filter-field p { display: block; margin: 0 0 0.35rem; font-weight: 700; }
--
style.css-154-}
style.css-155-
style.css-156-@media print {
style.css:157:  :root, html[data-theme="dark"] { color-scheme: light; --surface: #fff; --surface-raised: #fff; --text: #000; --muted: #333; --line: #888; --link: #000; }
style.css:158:  .skip-link, .site-nav, .theme-toggle, .lesson-controls, .lesson-empty { display: none !important; }
style.css-159-  .page-shell { padding-block: 1.5rem; }
style.css-160-  .course-hero, .day-grid, .lesson-grid, .resources-section ul { grid-template-columns: 1fr; }
style.css-161-  a { color: #000; }
--
index.html-1-<!doctype html>
index.html:2:<html lang="th" data-theme="light">
index.html-3-  <head>
index.html-4-    <meta charset="utf-8">
index.html-5-    <meta name="viewport" content="width=device-width, initial-scale=1">
--
index.html-19-        </div>
index.html-20-        <nav class="site-nav" aria-label="เมนูหลัก">
index.html-21-          <a href="#workshop">แผน workshop</a>
index.html:22:          <a href="#lessons">บทเรียน</a>
index.html-23-          <a href="#resources">แหล่งเรียนต่อ</a>
index.html-24-          <a href="/handbook/">คู่มือการเรียน</a>
index.html-25-          <a href="/resources/">ทรัพยากร</a>
index.html-26-        </nav>
index.html:27:        <button id="theme-toggle" class="theme-toggle" type="button" aria-pressed="false" hidden>
index.html-28-          เปลี่ยนเป็นโหมดมืด
index.html-29-        </button>
index.html-30-      </div>
--
index.html-39-          <p class="hero-summary">เส้นทางเรียนรู้เพื่อเริ่มสร้างเว็บไซต์ด้วย AI ตั้งแต่เครื่องมือและพื้นฐาน ไปจนถึงการส่งมอบที่ตรวจสอบได้</p>
index.html-40-          <p class="hero-actions">
index.html-41-            <a href="/learn/lessons/00-setup-and-web-basics/">เริ่มจากบทเรียน 00</a>
index.html:42:            <a href="#lessons">ดูบทเรียนทั้งหมด</a>
index.html-43-          </p>
index.html-44-        </div>
index.html-45-        <div class="learning-preview" aria-label="ภาพรวมเส้นทางการทำงาน">

EXIT 0

EXECUTED COMMAND
/bin/bash -lc "nl -ba brief.md | sed -n '1,420p'
nl -ba evidence.csv | sed -n '1,240p'
printf '\\n--- index/main facts ---\\n'
nl -ba index.html | sed -n '1,280p'
nl -ba main.js | sed -n '1,180p'
printf '\\n--- decisions ---\\n'
nl -ba implementation-decisions.md | sed -n '1,360p'"
OUTPUT
     1	# Brief — เว็บไซต์ตัวอย่างรายวิชา 977-121
     2	
     3	## กรอบงานและสถานะข้อมูล
     4	
     5	- **ขอบเขตผลลัพธ์:** เอกสารสังเคราะห์สำหรับหน้า static HTML/CSS/JS ภาษาไทยหน้าเดียวในอนาคต; เอกสารนี้ไม่ใช่หน้าเว็บ และไม่มีการทำ web research
     6	- **สถานะ:** Draft สำหรับให้เจ้าของตรวจสอบก่อนเข้าสู่ semantic HTML
     7	- **ตำแหน่งผลิตภัณฑ์:** เว็บไซต์ตัวอย่างประกอบการเรียนที่ `/examples/course-website/` ไม่ใช่ระบบมหาวิทยาลัยอย่างเป็นทางการ
     8	- **ข้อจำกัด:** ไม่สร้างตรา/โลโก้มหาวิทยาลัย ข้อมูลผู้สอน หน่วยกิต ตารางภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร บัญชี LMS หรือ login/รับสมัครจำลอง
     9	
    10	## FACT
    11	
    12	- ชื่อรายวิชา: **977-121 Module: Website Design and Development**
    13	- สถาบันที่ระบุ: **มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต / Prince of Songkla University, Phuket Campus**
    14	- **AI Web Studio — ออกแบบและพัฒนาเว็บไซต์ด้วย AI** เป็น workshop ภายในรายวิชา ระยะเวลา 2 วัน × 4 ชั่วโมง (รวม 8 ชั่วโมง) และมีพัก 10 นาทีต่อวัน; ไม่ใช่ชั่วโมง หน่วยกิต หรือประมวลรายวิชาฉบับเต็มของมหาวิทยาลัย
    15	- มีบทเรียนจริง 11 บท (00–10) และมีปลายทางบทเรียน/ทรัพยากรตาม content inventory ด้านล่าง
    16	- visual system ที่มีอยู่ใช้ Inter + Noto Sans Thai, light เป็นค่าเริ่มต้น และใช้สีเขียวอย่างจำกัดเพื่อเน้น
    17	
    18	## INFERENCE
    19	
    20	- ผู้เข้าชมหลักต้องการตอบคำถามเร็ว ๆ ว่า “เริ่มตรงไหน”, “มีบทเรียนใดบ้าง” และ “workshop สองวันนี้ทำอะไร”; ดังนั้นหน้าเดียวควรให้ทางเลือกเริ่มเรียนและแผน Day 1/Day 2 อยู่ก่อนเนื้อหารายละเอียด
    21	- CTA ควรพาไปยังปลายทางที่มีอยู่จริงเท่านั้น และป้ายกำกับต้องบอกชนิด/สถานะของปลายทางอย่างตรงไปตรงมา โดยเฉพาะลิงก์บทความแบบทีละขั้นที่ยังอยู่ระหว่างสร้าง
    22	- เนื่องจาก workshop เป็นเพียงส่วนหนึ่งของ module จึงควรนำเสนอเป็น “แผน workshop” ไม่ใช่ตารางสอนหรือคำอธิบายรายวิชาฉบับสมบูรณ์
    23	
    24	## PROPOSAL
    25	
    26	### เป้าหมายและ audience
    27	
    28	**เป้าหมายหลัก:** ช่วยผู้เรียนค้นพบเส้นทางเริ่มเรียน เข้าถึงบทเรียนจริง และเข้าใจขอบเขตของ AI Web Studio workshop โดยไม่ทำให้เข้าใจว่าเป็นเว็บไซต์ทางการหรือระบบรับสมัคร
    29	
    30	**Audience หลัก:** ผู้เรียนที่ต้องการเริ่มทำเว็บไซต์ด้วย AI และต้องเลือกบทเรียน/ดูภาพรวม workshop ก่อนเข้าเนื้อหา
    31	
    32	**Audience รอง:** ผู้สอนหรือผู้ทบทวนสื่อที่ต้องการตรวจรายการบทเรียนและปลายทางของหลักสูตรอย่างรวดเร็ว
    33	
    34	### ข้อเสนอคุณค่า (value proposition)
    35	
    36	“เส้นทางเรียนรู้เพื่อออกแบบและพัฒนาเว็บไซต์ด้วย AI: เริ่มจากเครื่องมือและพื้นฐาน ไปจนถึงการส่งมอบที่ตรวจสอบได้ พร้อม workshop สองวันเป็นส่วนหนึ่งของ module.”
    37	
    38	### CTA และปลายทาง
    39	
    40	| ระดับ | ป้าย CTA ที่เสนอ | ปลายทาง | หมายเหตุ |
    41	| --- | --- | --- | --- |
    42	| หลัก | `เริ่มจากบทเรียน 00` | `/learn/lessons/00-setup-and-web-basics/` | เริ่มต้นที่จุดเข้าเรียนชัดเจน |
    43	| รอง | `ดูบทเรียนทั้งหมด` | `/` | ใช้เมื่อหน้าเว็บไซต์สื่อหลักสูตรแสดงรายการเรียน; ยืนยัน label ใน implementation อีกครั้ง |
    44	| รอง | `ดูแผน AI Web Studio 2 วัน` | anchor `#workshop` | เลื่อนภายในหน้า ไม่อ้างว่าเป็นตารางรายวิชาเต็ม |
    45	| รอง | `เปิดคู่มือการเรียน` | `/handbook/` | ปลายทางที่มีจริง |
    46	| รอง | `ดูทรัพยากร` | `/resources/` | ปลายทางที่มีจริง |
    47	| บริบท | `อ่านการสร้างทีละขั้น` | `/learn/labs/build-course-website-step-by-step/` | ติดป้าย “กำลังสร้าง” จนกว่าจะยืนยันว่าเผยแพร่แล้ว |
    48	| เครดิต | `Rawinnipa` | `https://rawinsoft.com/` | ลิงก์ผู้ออกแบบ/ผู้จัดทำสื่อเท่านั้น ไม่อ้าง partnership หรือเจ้าของมหาวิทยาลัย |
    49	
    50	### ลำดับ section ของหน้าเดียว
    51	
    52	1. **Utility/header** — ชื่อรายวิชา, สถาบัน, ป้าย “เว็บไซต์ตัวอย่างประกอบการเรียน”, การข้ามไปเนื้อหาหลัก (skip link), สวิตช์ theme
    53	2. **Hero** — ชื่อรายวิชาเต็ม, ชื่อ workshop, value proposition, CTA หลัก และ CTA ดู workshop
    54	3. **ขอบเขต AI Web Studio** — ข้อความชัดเจนว่าเป็นส่วนหนึ่งของ module; 2 วัน × 4 ชั่วโมง, พัก 10 นาที/วัน, รวม 8 ชั่วโมง; ไม่แทนรายละเอียดรายวิชาฉบับมหาวิทยาลัย
    55	4. **แผน workshop Day 1 / Day 2** — สรุปกิจกรรมตามระดับหัวข้อเท่านั้น; ไม่ประดิษฐ์ตารางเวลาเต็มหรือผลการประเมิน
    56	5. **เส้นทางบทเรียน** — รายการ 00–10 พร้อมชื่อและลิงก์ที่มีจริง; search/filter แบบ optional: ทั้งหมด, Day 1, Day 2 โดยต้องประกาศเกณฑ์การจัดกลุ่มก่อนใช้
    57	6. **Labs และแหล่งเรียนต่อ** — ลิงก์ labs ที่มีจริง, handbook และ resources; ลิงก์ “อ่านการสร้างทีละขั้น” พร้อมป้าย “กำลังสร้าง”
    58	7. **ข้อจำกัด/ความโปร่งใส** — ย้ำสถานะเว็บไซต์ตัวอย่าง; ไม่มี login, รับสมัคร, LMS หรือข้อมูลทางวิชาการที่ยังไม่ยืนยัน
    59	8. **Footer** — ชื่อรายวิชาและ PSU Phuket เป็นข้อความ, ลิงก์ Rawinnipa ตามขอบเขตเครดิต; ไม่มีตราหรือโลโก้ที่สร้างขึ้น
    60	
    61	### Content inventory
    62	
    63	| กลุ่ม | เนื้อหาที่แสดง | ปลายทาง |
    64	| --- | --- | --- |
    65	| รายวิชา | 977-121 Module: Website Design and Development; มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต / Prince of Songkla University, Phuket Campus | ไม่มีลิงก์สถาบันที่ยืนยัน |
    66	| Workshop | AI Web Studio — ออกแบบและพัฒนาเว็บไซต์ด้วย AI; 2 วัน × 4 ชั่วโมง = 8 ชั่วโมง; พัก 10 นาที/วัน | `#workshop` |
    67	| บทเรียน 00 | เตรียมเครื่องและเข้าใจว่าเว็บทำงานอย่างไร | `/learn/lessons/00-setup-and-web-basics/` |
    68	| บทเรียน 01 | พื้นฐาน Vibe Coding สำหรับเว็บที่ส่งมอบได้จริง | `/learn/lessons/01-vibe-coding-foundations/` |
    69	| บทเรียน 02 | Agent Skills, MCP และ Plugins โดยไม่ทำให้บริบทพัง | `/learn/lessons/02-agent-skills/` |
    70	| บทเรียน 03 | Specs และ Prompts สำหรับเว็บบริษัท, Catalog และเว็บ animation | `/learn/lessons/03-specs-and-prompts/` |
    71	| บทเรียน 04 | ออกแบบ, ภาพ และคุณภาพก่อนเขียนหน้าเว็บ | `/learn/lessons/04-design-and-assets/` |
    72	| บทเรียน 05 | เว็บบริษัท: contact form ที่รันกับ demo นี้ได้จริง | `/learn/lessons/05-company-website/` |
    73	| บทเรียน 06 | เว็บเช่าอุปกรณ์: availability และ capacity ของ demo ที่รันได้จริง | `/learn/lessons/06-rental-and-data/` |
    74	| บทเรียน 07 | GSAP product story, storefront และ quote demo | `/learn/lessons/07-gsap-storefront/` |
    75	| บทเรียน 08 | รันและตรวจ deployment path ของโปรเจกต์ Cloudflare นี้ | `/learn/lessons/08-cloudflare-deploy/` |
    76	| บทเรียน 09 | Production Operations: security, observability, rollback และต้นทุน | `/learn/lessons/09-production-operations/` |
    77	| บทเรียน 10 | สร้างเว็บของตนเองและส่งมอบอย่างตรวจสอบได้ | `/learn/lessons/10-capstone-and-handoff/` |
    78	| Labs/ทรัพยากร | install AI tools; research-to-brand website; design tools and MCP; resources; handbook | `/learn/labs/install-ai-tools/`; `/learn/labs/research-to-brand-website/`; `/learn/labs/design-tools-and-mcp/`; `/resources/`; `/handbook/` |
    79	
    80	### States
    81	
    82	| State | ข้อเสนอพฤติกรรม/ข้อความ |
    83	| --- | --- |
    84	| Default | แสดง hero, CTA, workshop summary และรายการบทเรียนทั้งหมด |
    85	| Light (default) | พื้น `#F7F7F7`, ข้อความ `#0A0A0A`, accent `#3EDC81` พร้อมข้อความเข้ม, ข้อความเขียวบนพื้นอ่อน `#17653F` |
    86	| Dark | canvas `#0A0A0A`, surface `#171717`, ข้อความ `#F7F7F7`; รักษา contrast และไม่ใช้เขียวเป็นข้อความหลักบนพื้นมืดหากยังไม่ตรวจ contrast |
    87	| Theme preference | ใช้ light เป็น default; หากมีสวิตช์ ต้องมองเห็นสถานะและทำงานด้วยคีย์บอร์ด |
    88	| Lesson filter/search (optional) | แสดงผล “ไม่พบบทเรียนที่ตรงกัน” พร้อมปุ่ม/ลิงก์คืนค่า; filter Day 1/Day 2 ใช้ได้ต่อเมื่อเจ้าของยืนยัน mapping |
    89	| CTA pending | `อ่านการสร้างทีละขั้น` มีป้าย “กำลังสร้าง” และไม่อ้างว่าอ่านได้แล้ว |
    90	| Link failure/unknown | ไม่สร้างหน้า 404 หรือ loading simulation; ใช้เฉพาะปลายทางที่ S5 ระบุ |
    91	| Print | พื้นกระดาษขาว, ข้อความอ่านได้, ไม่พึ่งสีอย่างเดียวเพื่อสื่อความหมาย |
    92	
    93	### Responsive
    94	
    95	- **Mobile ก่อน:** หนึ่งคอลัมน์, CTA กว้างแตะง่าย, nav ไม่บังคับเลื่อนแนวนอน, lesson cards เรียงแนวตั้ง
    96	- **Tablet:** hero และ workshop สามารถจัดสองคอลัมน์เมื่อยังเหลือพื้นที่อ่านง่าย; filters อยู่ก่อนรายการผลลัพธ์
    97	- **Desktop:** ใช้ความกว้างข้อความจำกัดเพื่อการอ่าน, lesson grid หลายคอลัมน์ตามพื้นที่, header ยังเข้าถึง CTA หลักได้
    98	- ทุกขนาด: ไม่ซ่อนเนื้อหาสำคัญเพียงเพราะ viewport, รองรับ text zoom/reflow, และไม่ยึดความหมายด้วย hover เพียงอย่างเดียว
    99	
   100	### Accessibility acceptance checks
   101	
   102	- [ ] ใช้ semantic landmarks (`header`, `nav`, `main`, `section`, `footer`) และลำดับ heading ไม่ข้ามระดับ
   103	- [ ] มี skip link; ทุก CTA/ลิงก์เข้าถึงด้วยคีย์บอร์ด และ focus ชัดเจน
   104	- [ ] สี light/dark และทุกสถานะ focus/hover/selected ผ่าน contrast ที่เหมาะสม; สีเขียวไม่ใช่ตัวบอกความหมายเพียงอย่างเดียว
   105	- [ ] สวิตช์ theme และ filter/search (หากสร้าง) มี accessible name, state และประกาศการเปลี่ยนแปลงผลลัพธ์อย่างเหมาะสม
   106	- [ ] ข้อความไทยใช้ Noto Sans Thai และข้อความ Latin ใช้ Inter จาก font ในระบบ; ไม่มี external font
   107	- [ ] ขนาดเป้าหมายสัมผัสเพียงพอ, หน้า reflow ได้ที่ความกว้างแคบ/zoom, และไม่มี horizontal overflow โดยไม่จำเป็น
   108	- [ ] ไม่มีภาพที่ต้องพึ่งพาเพื่อเข้าใจเนื้อหา; ถ้ามี SVG ตกแต่งต้องซ่อนจาก assistive technology
   109	- [ ] โครงสร้าง print เป็นพื้นขาวและยังอ่านลิงก์/ป้าย “กำลังสร้าง” ได้
   110	
   111	## ทางเลือกภาพ (ไม่สร้าง raster/ตรามหาวิทยาลัย)
   112	
   113	### ทางเลือก A — Type-led learning map
   114	
   115	ใช้ typography เป็นภาพหลัก: หมายเลขบทเรียน 00–10 ขนาดใหญ่, เส้นทาง/จุดสถานะด้วย CSS หรือ SVG ธรรมดา, และ chip “Day 1/Day 2”. ภาพสื่อการเดินทางผ่านเนื้อหาโดยไม่ต้องใช้รูปถ่ายหรือสินทรัพย์ใหม่; ใช้ green เฉพาะจุดเริ่มต้น, CTA และสถานะที่ได้รับการยืนยัน.
   116	
   117	### ทางเลือก B — Editorial workshop cards
   118	
   119	ใช้การ์ดขาว/ผิว dark ที่มีตัวเลข “Day 1”, “Day 2” และ glyph จาก HTML/SVG ธรรมดา (เช่น cursor, bracket, check) พร้อมภาพพิมพ์ขนาดใหญ่. ให้บรรยากาศ workshop ชัด แต่ต้องระวังไม่ทำให้ผู้ใช้เข้าใจว่าบัตรเหล่านี้คือกำหนดการรายวิชาทางการ.
   120	
   121	### Draft ที่เลือก — ทางเลือก A
   122	
   123	เลือก **Type-led learning map** เพราะสอดคล้องกับแบรนด์เดิมที่เรียบ ใช้สีเขียวจำกัด และให้บทเรียนจริงเป็นศูนย์กลาง. ลดความเสี่ยงการสร้างภาพ/ตรามหาวิทยาลัยหรือการใส่บริบท workshop เกินข้อเท็จจริง. จะใช้เฉพาะข้อความ, HTML และ SVG ธรรมดาตามสินทรัพย์ที่อนุญาต.
   124	
   125	## GAP — ต้องถามเจ้าของก่อน implementation
   126	
   127	1. ต้องการให้ชื่อไทยของรายวิชามีหรือไม่? ปัจจุบันยืนยันเพียงชื่อ `977-121 Module: Website Design and Development`.
   128	2. Mapping ที่ได้รับอนุมัติของบทเรียนใดอยู่ Day 1 และ Day 2 คืออะไร? จนกว่าจะยืนยัน ต้องไม่เปิด filter Day 1/Day 2 หรือใส่ป้ายรายบท.
   129	3. CTA `ดูบทเรียนทั้งหมด` ควรชี้ไปหน้าใด/anchor ใด? S5 ยืนยันเพียง `/` เป็นเว็บไซต์สื่อหลักสูตร ไม่ได้ยืนยันส่วนรายการบทเรียน.
   130	4. ปลายทาง `/learn/labs/build-course-website-step-by-step/` เผยแพร่เมื่อใด? ก่อนนั้นต้องคงป้าย “กำลังสร้าง” หรือซ่อน CTA.
   131	5. อนุมัติข้อความ disclaimer ว่า “เว็บไซต์ตัวอย่างประกอบการเรียน ไม่ใช่ระบบมหาวิทยาลัยอย่างเป็นทางการ” หรือมีถ้อยคำที่เจ้าของกำหนดหรือไม่?
   132	6. ผู้ใช้ต้องการ theme toggle จริงหรือเพียงรองรับ system preference? ข้อกำหนด design system ระบุ light default และ dark palette แต่ยังไม่ยืนยัน interaction.
   133	7. ยืนยันว่าต้องการแสดงลิงก์ Rawinnipa ใน footer หรือไม่; หากแสดงให้ใช้เพียงเครดิตผู้ออกแบบ/ผู้จัดทำสื่อ.
   134	8. ผู้สอน หน่วยกิต ภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร และ LMS จะได้รับอนุมัติให้แสดงหรือไม่? ถ้าไม่ ต้องคงไม่แสดงทั้งหมด.
   135	
     1	source_id,classification,claim,evidence,brief_use
     2	S1,FACT,"ชื่อรายวิชาและสถาบัน","977-121 Module: Website Design and Development; มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต / Prince of Songkla University, Phuket Campus","ชื่อใน header/hero/footer และการระบุสถาบันเป็นข้อความ"
     3	S2,FACT,"AI Web Studio เป็น workshop 2 วัน x 4 ชั่วโมง รวม 8 ชั่วโมง พัก 10 นาทีต่อวัน และเป็นส่วนหนึ่งของรายวิชา","design-system/course.json และ docs/instructor/course-guide.md ตามข้อมูลตั้งต้น; ไม่ใช่ชั่วโมง หน่วยกิต หรือประมวลรายวิชาฉบับมหาวิทยาลัยทั้งหมด","section ขอบเขตและสรุป workshop; ห้ามทำตารางรายวิชาเต็มหรืออ้างหน่วยกิต"
     4	S3,FACT,"course shell ใช้ Inter และ Noto Sans Thai; light/dark palette และข้อจำกัดแบรนด์","DESIGN.md และ Rawinnipa Brand Guidelines v1.0 ตามข้อมูลตั้งต้น: light #F7F7F7/#0A0A0A/#3EDC81/#17653F; dark #0A0A0A/#171717/#F7F7F7; green จำกัด; visible focus; print white; rawinsoft.com เป็นเครดิตเท่านั้น; ห้ามสร้างตรา/โลโก้มหาวิทยาลัย","states, responsive/accessibility, visual direction และ footer"
     5	S4,FACT,"มีบทเรียนจริง 11 บท 00-10 พร้อมชื่อและ URL","รายการบทเรียนและเส้นทาง /learn/lessons/00-setup-and-web-basics/ ถึง /learn/lessons/10-capstone-and-handoff/ ที่ให้มา","content inventory และ lesson-path section"
     6	S5,FACT,"มีปลายทางหลัก resources handbook labs example และบทความทีละขั้นกำลังสร้าง","/; /resources/; /handbook/; labs 3 แห่ง; /examples/course-website/; /learn/labs/build-course-website-step-by-step/ กำลังสร้าง","CTA และการติดป้าย pending"
     7	S6,FACT,"ใช้ไฟล์ font ภายในและ HTML/SVG ธรรมดาโดยไม่ต้องสร้าง raster หรือโหลด font ภายนอก","/fonts/Inter-Regular.woff2; /fonts/Inter-Bold.woff2; /fonts/NotoSansThai-Regular.woff2; /fonts/NotoSansThai-Bold.woff2","ข้อเสนอภาพ, typography และ accessibility"
     8	S1-S6,INFERENCE,"ผู้เรียนต้องการจุดเริ่ม เลือกบทเรียน และดูภาพรวม workshop ก่อนรายละเอียด","อนุมานจากข้อเสนอ prototype ในข้อมูลตั้งต้น ร่วมกับรายการบทเรียนและข้อจำกัด workshop","จัด hero, CTA เริ่มจากบทเรียน 00, workshop ก่อน lesson index"
     9	S2-S5,INFERENCE,"Day 1/Day 2 filter ต้องไม่เปิดจนกว่าจะมี mapping รายบทที่ยืนยัน","มีเพียงการยืนยันว่า workshop 2 วัน แต่ไม่มีการจัดบทเรียนลงวัน","GAP และ state ของ filter"
    10	S3,GAP,"theme toggle เป็น interaction ที่เป็นไปได้แต่ยังไม่ยืนยัน","ข้อมูลกำหนด light default และ dark palette แต่ไม่ระบุว่าต้องมีสวิตช์","เสนอเป็น state/คำถามยืนยัน ไม่ใช่ข้อกำหนดที่ยืนยันแล้ว"
    11	S5,GAP,"CTA ดูบทเรียนทั้งหมดชี้ / ได้ชั่วคราวแต่ต้องยืนยัน anchor/เนื้อหาปลายทาง","S5 ระบุ / เป็นเว็บไซต์สื่อหลักสูตร แต่ไม่ยืนยันว่าเป็น lesson index โดยตรง","GAP ก่อน implementation"
    12	S1-S6,PROPOSAL,"เลือกภาพ Type-led learning map เป็น draft","ใช้ typography หมายเลขบทเรียน เส้นทาง CSS/SVG และ green แบบจำกัด; ไม่ใช้ raster หรือตรามหาวิทยาลัย","visual direction draft"
    13	S1-S6,GAP,"ห้ามสร้างข้อมูลผู้สอน หน่วยกิต ภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร หรือ LMS","GAP ที่ระบุในข้อมูลตั้งต้น","ตัดออกจากหน้าและรวบรวมคำถามเจ้าของ"

--- index/main facts ---
     1	<!doctype html>
     2	<html lang="th" data-theme="light">
     3	  <head>
     4	    <meta charset="utf-8">
     5	    <meta name="viewport" content="width=device-width, initial-scale=1">
     6	    <meta name="description" content="เว็บไซต์ตัวอย่างประกอบการเรียนสำหรับ 977-121 Module: Website Design and Development">
     7	    <title>977-121 Module: Website Design and Development | AI Web Studio</title>
     8	    <link rel="stylesheet" href="style.css">
     9	  </head>
    10	  <body>
    11	    <a class="skip-link" href="#main-content">ข้ามไปยังเนื้อหาหลัก</a>
    12	
    13	    <header class="site-header">
    14	      <div class="header-inner">
    15	        <div class="course-identity">
    16	          <p class="eyebrow">เว็บไซต์ตัวอย่างประกอบการเรียน</p>
    17	          <p class="course-code">977-121 Module: Website Design and Development</p>
    18	          <p class="institution">มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต</p>
    19	        </div>
    20	        <nav class="site-nav" aria-label="เมนูหลัก">
    21	          <a href="#workshop">แผน workshop</a>
    22	          <a href="#lessons">บทเรียน</a>
    23	          <a href="#resources">แหล่งเรียนต่อ</a>
    24	          <a href="/handbook/">คู่มือการเรียน</a>
    25	          <a href="/resources/">ทรัพยากร</a>
    26	        </nav>
    27	        <button id="theme-toggle" class="theme-toggle" type="button" aria-pressed="false" hidden>
    28	          เปลี่ยนเป็นโหมดมืด
    29	        </button>
    30	      </div>
    31	    </header>
    32	
    33	    <main id="main-content" class="page-shell" tabindex="-1">
    34	      <section class="course-hero" aria-labelledby="hero-title">
    35	        <div class="hero-copy">
    36	          <p class="eyebrow">AI Web Studio</p>
    37	          <h1 id="hero-title">977-121 Module: Website Design and Development</h1>
    38	          <p class="hero-subtitle">ออกแบบและพัฒนาเว็บไซต์ด้วย AI</p>
    39	          <p class="hero-summary">เส้นทางเรียนรู้เพื่อเริ่มสร้างเว็บไซต์ด้วย AI ตั้งแต่เครื่องมือและพื้นฐาน ไปจนถึงการส่งมอบที่ตรวจสอบได้</p>
    40	          <p class="hero-actions">
    41	            <a href="/learn/lessons/00-setup-and-web-basics/">เริ่มจากบทเรียน 00</a>
    42	            <a href="#lessons">ดูบทเรียนทั้งหมด</a>
    43	          </p>
    44	        </div>
    45	        <div class="learning-preview" aria-label="ภาพรวมเส้นทางการทำงาน">
    46	          <p class="preview-label">ภาพรวมเส้นทางการทำงาน</p>
    47	          <ol>
    48	            <li>Brief</li>
    49	            <li>Build</li>
    50	            <li>Verify</li>
    51	            <li>Publish</li>
    52	          </ol>
    53	        </div>
    54	      </section>
    55	
    56	      <section class="content-section goals-section" aria-labelledby="goals-title">
    57	        <h2 id="goals-title">เป้าหมายของ workshop</h2>
    58	        <p>AI Web Studio เป็นส่วนหนึ่งของรายวิชา เพื่อช่วยผู้เรียนเลือกจุดเริ่มต้น เข้าถึงบทเรียนจริง และฝึกสร้างเว็บไซต์ด้วย AI อย่างมีขั้นตอน</p>
    59	        <ul>
    60	          <li>เข้าใจเครื่องมือและพื้นฐานของเว็บก่อนเริ่มลงมือ</li>
    61	          <li>ใช้ specs, prompts และเครื่องมือ AI เพื่อพัฒนาเว็บไซต์</li>
    62	          <li>ตรวจคุณภาพและส่งมอบงานที่ตรวจสอบได้</li>
    63	        </ul>
    64	        <p>workshop นี้ไม่ใช่รายละเอียดรายวิชาฉบับมหาวิทยาลัยหรือระบบมหาวิทยาลัยอย่างเป็นทางการ</p>
    65	      </section>
    66	
    67	      <section id="workshop" class="content-section workshop-section" aria-labelledby="workshop-title">
    68	        <h2 id="workshop-title">แผน AI Web Studio 2 วัน</h2>
    69	        <p>รวม 8 ชั่วโมง: 2 วัน วันละ 4 ชั่วโมง และพัก 10 นาทีต่อวัน</p>
    70	        <p>แผนนี้เป็นเส้นทางเลือกใช้คลังบทเรียนตามเวลาจริงในห้องเรียน ไม่ได้สัญญาว่าจะสอนครบทุกบทภายใน 8 ชั่วโมง</p>
    71	        <div class="day-grid">
    72	          <section class="day-card" aria-labelledby="day1-title">
    73	            <h3 id="day1-title">Day 1 — เริ่มต้น ออกแบบ และสร้างฐานงาน</h3>
    74	            <p>4 ชั่วโมง รวมพัก 10 นาที: เลือกกิจกรรมจากบท 00–05 เพื่อเตรียมเครื่องมือ วางบริบท และเริ่มทำเว็บไซต์</p>
    75	          </section>
    76	          <section class="day-card" aria-labelledby="day2-title">
    77	            <h3 id="day2-title">Day 2 — ขยายงาน ตรวจสอบ และส่งมอบ</h3>
    78	            <p>4 ชั่วโมง รวมพัก 10 นาที: เลือกกิจกรรมจากบท 06–10 เพื่อทำงานกับข้อมูล ประสบการณ์เว็บ การ deploy และการส่งมอบ</p>
    79	          </section>
    80	        </div>
    81	      </section>
    82	
    83	      <section id="lessons" class="content-section lessons-section" aria-labelledby="lessons-title">
    84	        <h2 id="lessons-title">เส้นทางบทเรียน</h2>
    85	        <p>บท 00–05 อยู่ในเส้นทาง Day 1 และบท 06–10 อยู่ในเส้นทาง Day 2 เพื่อใช้เลือกเนื้อหาใน workshop</p>
    86	
    87	        <div class="lesson-controls" hidden>
    88	          <div class="lesson-search-field">
    89	            <label for="lesson-search">ค้นหาบทเรียน</label>
    90	            <input id="lesson-search" type="search" autocomplete="off" placeholder="ค้นหาจากชื่อหรือคำอธิบายบทเรียน">
    91	          </div>
    92	          <div class="lesson-filter-field">
    93	            <p id="lesson-filter-label">เลือกเส้นทาง workshop</p>
    94	            <div class="lesson-filter-buttons" aria-labelledby="lesson-filter-label">
    95	              <button type="button" data-filter="all" aria-pressed="true">ทั้งหมด</button>
    96	              <button type="button" data-filter="day1" aria-pressed="false">Day 1</button>
    97	              <button type="button" data-filter="day2" aria-pressed="false">Day 2</button>
    98	            </div>
    99	          </div>
   100	          <button id="clear-search" type="button">ล้างการค้นหาและตัวกรอง</button>
   101	          <p id="lesson-status" role="status" aria-live="polite"></p>
   102	        </div>
   103	        <p id="lesson-empty" class="lesson-empty" hidden>ไม่พบบทเรียนที่ตรงกับการค้นหาและตัวกรองนี้</p>
   104	
   105	        <section class="lesson-day" aria-labelledby="lessons-day1-title">
   106	          <h3 id="lessons-day1-title">Day 1: บท 00–05</h3>
   107	          <div class="lesson-grid">
   108	          <article data-lesson data-day="day1">
   109	            <h4>00 — เตรียมเครื่องและเข้าใจว่าเว็บทำงานอย่างไร</h4>
   110	            <p>เตรียมเครื่องมือและทำความเข้าใจพื้นฐานการทำงานของเว็บก่อนเริ่มสร้างงาน</p>
   111	            <a href="/learn/lessons/00-setup-and-web-basics/">อ่านบทเรียน 00</a>
   112	          </article>
   113	          <article data-lesson data-day="day1">
   114	            <h4>01 — พื้นฐาน Vibe Coding สำหรับเว็บที่ส่งมอบได้จริง</h4>
   115	            <p>เรียนรู้พื้นฐาน Vibe Coding เพื่อสร้างเว็บที่พร้อมส่งมอบ</p>
   116	            <a href="/learn/lessons/01-vibe-coding-foundations/">อ่านบทเรียน 01</a>
   117	          </article>
   118	          <article data-lesson data-day="day1">
   119	            <h4>02 — Agent Skills, MCP และ Plugins โดยไม่ทำให้บริบทพัง</h4>
   120	            <p>ทำความเข้าใจ Agent Skills, MCP และ Plugins พร้อมดูแลบริบทการทำงาน</p>
   121	            <a href="/learn/lessons/02-agent-skills/">อ่านบทเรียน 02</a>
   122	          </article>
   123	          <article data-lesson data-day="day1">
   124	            <h4>03 — Specs และ Prompts สำหรับเว็บบริษัท, Catalog และเว็บ animation</h4>
   125	            <p>เขียน specs และ prompts สำหรับเว็บบริษัท catalog และเว็บที่มี animation</p>
   126	            <a href="/learn/lessons/03-specs-and-prompts/">อ่านบทเรียน 03</a>
   127	          </article>
   128	          <article data-lesson data-day="day1">
   129	            <h4>04 — ออกแบบ, ภาพ และคุณภาพก่อนเขียนหน้าเว็บ</h4>
   130	            <p>วางงานออกแบบ ภาพ และเกณฑ์คุณภาพก่อนเริ่มเขียนหน้าเว็บ</p>
   131	            <a href="/learn/lessons/04-design-and-assets/">อ่านบทเรียน 04</a>
   132	          </article>
   133	          <article data-lesson data-day="day1">
   134	            <h4>05 — เว็บบริษัท: contact form ที่รันกับ demo นี้ได้จริง</h4>
   135	            <p>สร้างเว็บบริษัทและ contact form ที่ทำงานกับ demo ได้จริง</p>
   136	            <a href="/learn/lessons/05-company-website/">อ่านบทเรียน 05</a>
   137	          </article>
   138	          </div>
   139	        </section>
   140	
   141	        <section class="lesson-day" aria-labelledby="lessons-day2-title">
   142	          <h3 id="lessons-day2-title">Day 2: บท 06–10</h3>
   143	          <div class="lesson-grid">
   144	          <article data-lesson data-day="day2">
   145	            <h4>06 — เว็บเช่าอุปกรณ์: availability และ capacity ของ demo ที่รันได้จริง</h4>
   146	            <p>พัฒนาเว็บเช่าอุปกรณ์ที่จัดการ availability และ capacity ของ demo ได้</p>
   147	            <a href="/learn/lessons/06-rental-and-data/">อ่านบทเรียน 06</a>
   148	          </article>
   149	          <article data-lesson data-day="day2">
   150	            <h4>07 — GSAP product story, storefront และ quote demo</h4>
   151	            <p>สร้าง product story, storefront และ quote demo ด้วย GSAP</p>
   152	            <a href="/learn/lessons/07-gsap-storefront/">อ่านบทเรียน 07</a>
   153	          </article>
   154	          <article data-lesson data-day="day2">
   155	            <h4>08 — รันและตรวจ deployment path ของโปรเจกต์ Cloudflare นี้</h4>
   156	            <p>รันโปรเจกต์และตรวจเส้นทาง deployment ของ Cloudflare</p>
   157	            <a href="/learn/lessons/08-cloudflare-deploy/">อ่านบทเรียน 08</a>
   158	          </article>
   159	          <article data-lesson data-day="day2">
   160	            <h4>09 — Production Operations: security, observability, rollback และต้นทุน</h4>
   161	            <p>ดูแล production ทั้งความปลอดภัย การสังเกตการณ์ การ rollback และต้นทุน</p>
   162	            <a href="/learn/lessons/09-production-operations/">อ่านบทเรียน 09</a>
   163	          </article>
   164	          <article data-lesson data-day="day2">
   165	            <h4>10 — สร้างเว็บของตนเองและส่งมอบอย่างตรวจสอบได้</h4>
   166	            <p>สร้างเว็บของตนเองและเตรียมการส่งมอบที่ตรวจสอบได้</p>
   167	            <a href="/learn/lessons/10-capstone-and-handoff/">อ่านบทเรียน 10</a>
   168	          </article>
   169	          </div>
   170	        </section>
   171	      </section>
   172	
   173	      <section id="resources" class="content-section resources-section" aria-labelledby="resources-title">
   174	        <h2 id="resources-title">Labs และแหล่งเรียนต่อ</h2>
   175	        <ul>
   176	          <li><a href="/learn/labs/install-ai-tools/">Lab: ติดตั้งเครื่องมือ AI</a></li>
   177	          <li><a href="/learn/labs/research-to-brand-website/">Lab: จากการค้นคว้าสู่เว็บไซต์แบรนด์</a></li>
   178	          <li><a href="/learn/labs/design-tools-and-mcp/">Lab: เครื่องมือออกแบบและ MCP</a></li>
   179	          <li><a href="/handbook/">เปิดคู่มือการเรียน</a></li>
   180	          <li><a href="/resources/">ดูทรัพยากร</a></li>
   181	          <li><a href="/learn/labs/build-course-website-step-by-step/">อ่านการสร้างทีละขั้น <span>(กำลังสร้าง)</span></a></li>
   182	        </ul>
   183	      </section>
   184	    </main>
   185	
   186	    <footer class="site-footer">
   187	      <p>977-121 Module: Website Design and Development · มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต</p>
   188	      <p>สื่อออกแบบและจัดทำโดย <a href="https://rawinsoft.com/">Rawinnipa</a></p>
   189	    </footer>
   190	    <script src="main.js" defer></script>
   191	  </body>
   192	</html>
     1	(() => {
     2	  "use strict";
     3	
     4	  const storageKey = "psu-course-website-theme-v1";
     5	  const root = document.documentElement;
     6	  const themeToggle = document.querySelector("#theme-toggle");
     7	  const controls = document.querySelector(".lesson-controls");
     8	  const search = document.querySelector("#lesson-search");
     9	  const filterButtons = [...document.querySelectorAll("[data-filter]")];
    10	  const clearSearch = document.querySelector("#clear-search");
    11	  const status = document.querySelector("#lesson-status");
    12	  const empty = document.querySelector("#lesson-empty");
    13	  const lessons = [...document.querySelectorAll("article[data-lesson][data-day]")];
    14	  const lessonDays = [...document.querySelectorAll(".lesson-day")];
    15	
    16	  let theme = "light";
    17	  let selectedFilter = "all";
    18	
    19	  try {
    20	    const savedTheme = window.localStorage.getItem(storageKey);
    21	    if (savedTheme === "light" || savedTheme === "dark") {
    22	      theme = savedTheme;
    23	    }
    24	  } catch (_) {
    25	    // Theme selection still works for this visit when storage is unavailable.
    26	  }
    27	
    28	  function setTheme(nextTheme) {
    29	    theme = nextTheme;
    30	    root.dataset.theme = theme;
    31	    const isDark = theme === "dark";
    32	    themeToggle.setAttribute("aria-pressed", String(isDark));
    33	    themeToggle.textContent = isDark ? "เปลี่ยนเป็นโหมดสว่าง" : "เปลี่ยนเป็นโหมดมืด";
    34	    themeToggle.setAttribute(
    35	      "aria-label",
    36	      isDark
    37	        ? "โหมดปัจจุบัน: มืด เปลี่ยนเป็นโหมดสว่าง"
    38	        : "โหมดปัจจุบัน: สว่าง เปลี่ยนเป็นโหมดมืด"
    39	    );
    40	  }
    41	
    42	  function normalise(value) {
    43	    return value.replace(/\s+/g, " ").trim().toLocaleLowerCase();
    44	  }
    45	
    46	  function lessonText(lesson) {
    47	    const title = lesson.querySelector("h4");
    48	    const description = lesson.querySelector("p");
    49	    return normalise(`${title?.textContent ?? ""} ${description?.textContent ?? ""}`);
    50	  }
    51	
    52	  function updateLessons() {
    53	    const query = normalise(search.value);
    54	    let count = 0;
    55	
    56	    lessons.forEach((lesson) => {
    57	      const matchesFilter = selectedFilter === "all" || lesson.dataset.day === selectedFilter;
    58	      const matchesQuery = query === "" || lessonText(lesson).includes(query);
    59	      const visible = matchesFilter && matchesQuery;
    60	      lesson.hidden = !visible;
    61	      if (visible) count += 1;
    62	    });
    63	
    64	    lessonDays.forEach((day) => {
    65	      day.hidden = !day.querySelector("article[data-lesson]:not([hidden])");
    66	    });
    67	    empty.hidden = count !== 0;
    68	    status.textContent = `พบบทเรียน ${count} จาก ${lessons.length} บท`;
    69	  }
    70	
    71	  function setFilter(nextFilter) {
    72	    selectedFilter = nextFilter;
    73	    filterButtons.forEach((button) => {
    74	      button.setAttribute("aria-pressed", String(button.dataset.filter === selectedFilter));
    75	    });
    76	    updateLessons();
    77	  }
    78	
    79	  if (themeToggle) {
    80	    themeToggle.hidden = false;
    81	    setTheme(theme);
    82	    themeToggle.addEventListener("click", () => {
    83	      const nextTheme = theme === "dark" ? "light" : "dark";
    84	      setTheme(nextTheme);
    85	      try {
    86	        window.localStorage.setItem(storageKey, nextTheme);
    87	      } catch (_) {
    88	        // Storage can be disabled without preventing the visual toggle.
    89	      }
    90	    });
    91	  }
    92	
    93	  if (controls && search && clearSearch && status && empty && lessons.length > 0) {
    94	    controls.hidden = false;
    95	    search.addEventListener("input", updateLessons);
    96	    filterButtons.forEach((button) => {
    97	      button.addEventListener("click", () => setFilter(button.dataset.filter));
    98	    });
    99	    clearSearch.addEventListener("click", () => {
   100	      search.value = "";
   101	      setFilter("all");
   102	      search.focus();
   103	    });
   104	    updateLessons();
   105	  }
   106	})();

--- decisions ---
     1	# ข้อกำหนดเพิ่มเติมที่ส่งจริงระหว่างการสร้าง
     2	
     3	D1 — Prompt02: Day1 บท00–05, Day2บท06–10 ยึด scripts/build.mjs dayData. ช่วงเนื้อหานี้ไม่เปลี่ยน8hworkshopและพักวันละ10นาที
     4	D2 — Prompt02: CTAรองไป #lessons, CTAหลักไปบท00จริง /learn/lessons/00-setup-and-web-basics/, คู่มือไป/handbook/หรือ/resources/
     5	D3 — Prompt04: เพิ่มtheme toggle, lightdefaultแม้OSdark, dark/lightstoragekeypsu-course-website-theme-v1, storageerrorfallback, search/dayfilter/status/empty/resetและnoJSfallback
     6	
     7	ทั้งสามข้อเป็นคำสั่งและข้อมูลที่ parent ให้จริง ไม่มีการอนุมัติจากมหาวิทยาลัยหรือเจ้าของวิชาเต็มเพิ่มเติม

EXIT 0

EXECUTED COMMAND
/bin/bash -lc "rg --files -g '*snapshot*' -g '*evidence*' -g '*brief*' -g '*handoff*' -g '"'!node_modules'"' && git status --short && git diff -- brief.md evidence.csv handoff.md"
OUTPUT
brief.md
evidence.csv
?? ../../../.diagram-design
?? ../../../.gitattributes
?? ../../../.gitignore
?? ../../../CLAUDE.md
?? ../../../DESIGN.md
?? ../../../INFRASTRUCTURE.md
?? ../../../PROJECT_PLAN.md
?? ../../../README.md
?? ../../
?? ../../../design-system/
?? ../../../diagrams/
?? ../../../docs/
?? ../../../examples/
?? ../../../migrations/
?? ../../../package-lock.json
?? ../../../package.json
?? ../../../playwright.config.mjs
?? ../../../public/
?? ../../../scripts/
?? ../../../src/
?? ../../../tests/
?? ../../../training-skills/
?? ../../../tsconfig.json
?? ../../../worker-configuration.d.ts
?? ../../../wrangler.jsonc

EXIT 0

CODEX MESSAGE
พบหลักฐานตรงกันแล้ว: source ปัจจุบันใช้ `#lessons`, mapping Day 1/2 และ key `psu-course-website-theme-v1`; JSON ระบุผล 5/5 ผ่านจาก Parent-run Playwright ที่ `127.0.0.1:3320` และระบุชัดว่า *not yet tested in public*. ต่อไปจะบันทึกการยืนยันใหม่เป็นรายการต่อท้ายในหลักฐาน พร้อมเปลี่ยน GAP ที่ถูกตอบแล้วเป็น Confirmed โดยคงร่องรอยรอบแรก.

FILE CHANGES
[
  {
    "path": "<workspace>/brief.md",
    "kind": "update"
  },
  {
    "path": "<workspace>/evidence.csv",
    "kind": "update"
  },
  {
    "path": "<workspace>/handoff.md",
    "kind": "add"
  }
]

EXECUTED COMMAND
/bin/bash -lc "git -C <course-repository>/artifacts/course-walkthrough diff --check -- workspace/brief.md workspace/evidence.csv workspace/handoff.md && git -C <course-repository>/artifacts/course-walkthrough diff -- workspace/brief.md workspace/evidence.csv workspace/handoff.md && printf '\\n--- requirement evidence ---\\n' && rg -n -i '00–05|06–10|#lessons|psu-course-website-theme-v1|parent runner|not yet tested in public|ผู้สอน|หน่วยกิต|เกณฑ์คะแนน|LMS|STATUS_CHANGE' brief.md evidence.csv handoff.md && printf '\\n--- protected source remains unmodified in diff ---\\n' && git -C <course-repository>/artifacts/course-walkthrough diff --name-only -- workspace/index.html workspace/style.css workspace/main.js"
OUTPUT

--- requirement evidence ---
handoff.md:12:| `evidence.csv` | เก็บหลักฐานรอบแรกไว้ แล้วเพิ่ม FACT/VERIFIED/STATUS_CHANGE ของ D1–D3 และสถานะ public ที่ยังเป็น GAP |
handoff.md:14:| `browser-verification.json` | ผลทดสอบที่ parent runner แนบมา; ไม่ได้รันซ้ำ |
handoff.md:20:- CTA รอง `ดูบทเรียนทั้งหมด` → `#lessons` (ไม่ใช่ `/`)
handoff.md:25:- Day 1 = บท 00–05; Day 2 = บท 06–10 จาก `dayData`. เป็นเส้นทางเลือกเนื้อหา ไม่ได้ทำให้ workshop 8 ชั่วโมงครอบคลุมทุกบทโดยอัตโนมัติ.
handoff.md:26:- Theme toggle: light เป็น default แม้ OS dark; หลังผู้ใช้เลือกจึงใช้/บันทึกค่าด้วย storage key `psu-course-website-theme-v1`; หาก storage ใช้ไม่ได้ toggle ยังทำงานใน session นั้น.
handoff.md:31:`browser-verification.json` ระบุว่า **parent runner** เป็นผู้รัน Playwright (`npx playwright test tests/course-website.spec.mjs --reporter=json`) ที่ `http://127.0.0.1:3320` ไม่ใช่การรัน browser โดย Codex รอบนี้. ผล: 5 expected, 0 unexpected, 0 flaky; ครอบคลุม mapping 11 บท, search/filter/reset, default-light/storage fallback, no-JS, keyboard, viewport และ axe.
handoff.md:35:- ไม่มีหลักฐาน deploy/public; JSON ระบุ `publication: not yet tested in public`.
handoff.md:36:- ยังไม่ยืนยันข้อมูลผู้สอน, หน่วยกิต, ภาคเรียน, เกณฑ์คะแนน, ช่องทางสมัคร หรือ LMS — ต้องไม่อ้างว่าได้รับการยืนยันหรือแสดงข้อมูลเหล่านี้.
evidence.csv:3:S2,FACT,"AI Web Studio เป็น workshop 2 วัน x 4 ชั่วโมง รวม 8 ชั่วโมง พัก 10 นาทีต่อวัน และเป็นส่วนหนึ่งของรายวิชา","design-system/course.json และ docs/instructor/course-guide.md ตามข้อมูลตั้งต้น; ไม่ใช่ชั่วโมง หน่วยกิต หรือประมวลรายวิชาฉบับมหาวิทยาลัยทั้งหมด","section ขอบเขตและสรุป workshop; ห้ามทำตารางรายวิชาเต็มหรืออ้างหน่วยกิต"
evidence.csv:13:S1-S6,GAP,"ห้ามสร้างข้อมูลผู้สอน หน่วยกิต ภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร หรือ LMS","GAP ที่ระบุในข้อมูลตั้งต้น","ตัดออกจากหน้าและรวบรวมคำถามเจ้าของ"
evidence.csv:14:D1,FACT,"Day 1 ใช้บท 00–05 และ Day 2 ใช้บท 06–10","Prompt02 จาก parent; `scripts/build.mjs` dayData; implementation-decisions.md D1","ยืนยัน day labels และ Day 1/Day 2 filter; เป็นเส้นทางคลังบทเรียน ไม่เปลี่ยน workshop 8 ชั่วโมงหรือพัก 10 นาที/วัน"
evidence.csv:15:D2,FACT,"CTA รอง ดูบทเรียนทั้งหมด ชี้ไป #lessons","Prompt02 จาก parent; implementation-decisions.md D2; index.html hero CTA","ใช้ anchor ภายในหน้า ไม่ใช้ / ที่เคยเป็นสมมติฐาน"
evidence.csv:16:D3,FACT,"มี theme toggle โดย light เป็น default แม้ OS dark และเก็บเฉพาะตัวเลือกที่ผู้ใช้กด","Prompt04 จาก parent; implementation-decisions.md D3; main.js storage key psu-course-website-theme-v1","toggle ใช้ได้เมื่อ storage ผิดพลาด; ไม่ใช้ system preference เป็นตัวเลือกแทนผู้ใช้"
evidence.csv:18:V1,GAP,"สถานะเผยแพร่สาธารณะยังไม่ยืนยัน","browser-verification.json publication: not yet tested in public","ห้ามอ้าง public deployment จนกว่าจะมีหลักฐานจากขั้น deploy"
evidence.csv:19:S2-S5,STATUS_CHANGE,"GAP รอบแรก: Day 1/Day 2 filter ต้องรอ mapping รายบท","Snapshot รอบแรกแยกเก็บแล้ว; ถูกแทนสถานะด้วย D1","CONFIRMED — mapping 00–05 / 06–10 ได้รับคำตอบแล้ว"
evidence.csv:20:S5,STATUS_CHANGE,"GAP รอบแรก: CTA ดูบทเรียนทั้งหมดต้องยืนยันปลายทาง","Snapshot รอบแรกแยกเก็บแล้ว; ถูกแทนสถานะด้วย D2","CONFIRMED — ใช้ #lessons ไม่ใช่ /"
evidence.csv:21:S3,STATUS_CHANGE,"GAP รอบแรก: theme toggle ยังไม่ยืนยัน","Snapshot รอบแรกแยกเก็บแล้ว; ถูกแทนสถานะด้วย D3","CONFIRMED — light default, explicit-choice storage และ fallback"
brief.md:8:- **ข้อจำกัด:** ไม่สร้างตรา/โลโก้มหาวิทยาลัย ข้อมูลผู้สอน หน่วยกิต ตารางภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร บัญชี LMS หรือ login/รับสมัครจำลอง
brief.md:14:- **AI Web Studio — ออกแบบและพัฒนาเว็บไซต์ด้วย AI** เป็น workshop ภายในรายวิชา ระยะเวลา 2 วัน × 4 ชั่วโมง (รวม 8 ชั่วโมง) และมีพัก 10 นาทีต่อวัน; ไม่ใช่ชั่วโมง หน่วยกิต หรือประมวลรายวิชาฉบับเต็มของมหาวิทยาลัย
brief.md:17:- การจัดเส้นทางคลังบทเรียนที่ยืนยันแล้วจาก `scripts/build.mjs` `dayData`: Day 1 ใช้บท 00–05 และ Day 2 ใช้บท 06–10; เป็นการเลือกเนื้อหาตามเวลาใน workshop ไม่ได้หมายความว่าสอนครบทุกบทภายใน 8 ชั่วโมง
brief.md:18:- CTA รอง `ดูบทเรียนทั้งหมด` ที่ยืนยันแล้วชี้ไปยัง anchor `#lessons` ภายในหน้า ไม่ใช่ `/`
brief.md:19:- มี theme toggle ที่ยืนยันแล้ว: light เป็นค่าเริ่มต้นแม้ OS เป็น dark, อ่าน/บันทึกเฉพาะตัวเลือกที่ผู้ใช้กดด้วย key `psu-course-website-theme-v1`, และใช้งานต่อได้เมื่อ storage ผิดพลาด
brief.md:35:**Audience รอง:** ผู้สอนหรือผู้ทบทวนสื่อที่ต้องการตรวจรายการบทเรียนและปลายทางของหลักสูตรอย่างรวดเร็ว
brief.md:46:| รอง | `ดูบทเรียนทั้งหมด` | anchor `#lessons` | ยืนยันจาก Prompt02; เลื่อนไปยังรายการบทเรียนในหน้า ไม่ใช่ `/` |
brief.md:61:7. **ข้อจำกัด/ความโปร่งใส** — ย้ำสถานะเว็บไซต์ตัวอย่าง; ไม่มี login, รับสมัคร, LMS หรือข้อมูลทางวิชาการที่ยังไม่ยืนยัน
brief.md:90:| Theme preference | มี theme toggle ที่ยืนยันแล้ว; ใช้ light เป็น default แม้ OS เป็น dark, เก็บเฉพาะตัวเลือกที่ผู้ใช้กดใน `psu-course-website-theme-v1`, และ fallback ได้เมื่อ storage ใช้ไม่ได้ |
brief.md:91:| Lesson filter/search | แสดงผล “ไม่พบบทเรียนที่ตรงกัน” พร้อมปุ่ม/ลิงก์คืนค่า; filter Day 1/Day 2 ใช้ mapping ที่ยืนยันแล้ว: Day 1 บท 00–05, Day 2 บท 06–10 |
brief.md:134:| Mapping Day 1/Day 2 | **CONFIRMED** | Prompt02; `scripts/build.mjs` `dayData`; `implementation-decisions.md` D1 | แสดง/กรอง Day 1 บท 00–05 และ Day 2 บท 06–10 |
brief.md:135:| CTA `ดูบทเรียนทั้งหมด` | **CONFIRMED** | Prompt02; `implementation-decisions.md` D2 | ชี้ anchor `#lessons` |
brief.md:144:5. ผู้สอน หน่วยกิต ภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร และ LMS จะได้รับอนุมัติให้แสดงหรือไม่? ถ้าไม่ ต้องคงไม่แสดงทั้งหมด.
brief.md:148:`browser-verification.json` เป็นผล Playwright ที่ **parent runner** รัน ไม่ใช่การทดสอบ browser โดย Codex รอบนี้: 5 expected, 0 unexpected, 0 flaky ที่ `http://127.0.0.1:3320`. ครอบคลุม 11 บทและ mapping, search/filter/reset, light default เมื่อ OS dark พร้อม storage fallback, no-JS fallback, keyboard/viewport/axe. หลักฐานระบุ `publication: not yet tested in public`; จึงยังห้ามสรุปว่าเผยแพร่สาธารณะจนกว่าจะมีหลักฐานจากขั้น deploy.

--- protected source remains unmodified in diff ---

EXIT 0

FILE CHANGES
[
  {
    "path": "<workspace>/brief.md",
    "kind": "update"
  }
]

CODEX MESSAGE
เอกสารอัปเดตเสร็จแล้ว และกำลังตรวจโครงสร้าง CSV/ร่องรอยข้อกำหนดแบบอ่านอย่างเดียว; คำสั่งตรวจครั้งแรกถูก hook ปฏิเสธเพราะตีความ template string ของ Node ผิด จึงจะใช้คำสั่งที่ไม่มีการแทนค่าของ shell แทน.

EXECUTED COMMAND
/bin/bash -lc "node - <<'NODE'
const fs = require('fs');
const rows = fs.readFileSync('evidence.csv', 'utf8').trimEnd().split('\\n');
function parse(line) {
  const fields = []; let field = ''; let quoted = false;
  for (let i = 0; i < line.length; i += 1) {
    const ch = line[i];
    if (ch === '\"') {
      if (quoted && line[i + 1] === '\"') { field += ch; i += 1; }
      else quoted = "'!quoted;
    } else if (ch === '"',' && "'!quoted) { fields.push(field); field = '"''; }
    else field += ch;
  }
  if (quoted) throw new Error('unclosed quote');
  fields.push(field); return fields;
}
const invalid = rows.map((row, i) => [i + 1, parse(row).length]).filter((pair) => pair[1] "'!== 5);
if (invalid.length) throw new Error(JSON.stringify(invalid));
console.log('"'evidence.csv: ' + (rows.length - 1) + ' records, 5 columns each');
NODE"
OUTPUT
evidence.csv: 20 records, 5 columns each

EXIT 0

EXECUTED COMMAND
/bin/bash -lc "rg -n '"'^D[123],FACT|''^V1,VERIFIED|''^V1,GAP|''^S2-S5,STATUS_CHANGE|''^S5,STATUS_CHANGE|''^S3,STATUS_CHANGE'"' evidence.csv
rg -n '"'^## การเปลี่ยนสถานะ GAP|''^## หลักฐานตรวจที่ได้รับ|''^## GAP — ยัง'"' brief.md
rg -n '"'^## (ไฟล์|CTA ที่ยืนยัน|Interaction และ token|หลักฐานตรวจ|สิ่งที่ยังไม่ทำ)'"' handoff.md"
OUTPUT
14:D1,FACT,"Day 1 ใช้บท 00–05 และ Day 2 ใช้บท 06–10","Prompt02 จาก parent; `scripts/build.mjs` dayData; implementation-decisions.md D1","ยืนยัน day labels และ Day 1/Day 2 filter; เป็นเส้นทางคลังบทเรียน ไม่เปลี่ยน workshop 8 ชั่วโมงหรือพัก 10 นาที/วัน"
15:D2,FACT,"CTA รอง ดูบทเรียนทั้งหมด ชี้ไป #lessons","Prompt02 จาก parent; implementation-decisions.md D2; index.html hero CTA","ใช้ anchor ภายในหน้า ไม่ใช้ / ที่เคยเป็นสมมติฐาน"
16:D3,FACT,"มี theme toggle โดย light เป็น default แม้ OS dark และเก็บเฉพาะตัวเลือกที่ผู้ใช้กด","Prompt04 จาก parent; implementation-decisions.md D3; main.js storage key psu-course-website-theme-v1","toggle ใช้ได้เมื่อ storage ผิดพลาด; ไม่ใช้ system preference เป็นตัวเลือกแทนผู้ใช้"
17:V1,VERIFIED,"Parent-run browser suite ผ่าน 5 จาก 5 รายการ","browser-verification.json: Parent-run Playwright suite; expected 5 unexpected 0 flaky 0; baseURL http://127.0.0.1:3320","ครอบคลุม mapping, CTA/interaction ที่เกี่ยวข้อง, no-JS, keyboard, viewport และ axe; ไม่ใช่ผลที่ Codex รอบนี้รันเอง"
18:V1,GAP,"สถานะเผยแพร่สาธารณะยังไม่ยืนยัน","browser-verification.json publication: not yet tested in public","ห้ามอ้าง public deployment จนกว่าจะมีหลักฐานจากขั้น deploy"
19:S2-S5,STATUS_CHANGE,"GAP รอบแรก: Day 1/Day 2 filter ต้องรอ mapping รายบท","Snapshot รอบแรกแยกเก็บแล้ว; ถูกแทนสถานะด้วย D1","CONFIRMED — mapping 00–05 / 06–10 ได้รับคำตอบแล้ว"
20:S5,STATUS_CHANGE,"GAP รอบแรก: CTA ดูบทเรียนทั้งหมดต้องยืนยันปลายทาง","Snapshot รอบแรกแยกเก็บแล้ว; ถูกแทนสถานะด้วย D2","CONFIRMED — ใช้ #lessons ไม่ใช่ /"
21:S3,STATUS_CHANGE,"GAP รอบแรก: theme toggle ยังไม่ยืนยัน","Snapshot รอบแรกแยกเก็บแล้ว; ถูกแทนสถานะด้วย D3","CONFIRMED — light default, explicit-choice storage และ fallback"
128:## การเปลี่ยนสถานะ GAP ที่ได้รับคำตอบแล้ว
138:## GAP — ยังต้องถามเจ้าของก่อน implementation/เผยแพร่
146:## หลักฐานตรวจที่ได้รับ
7:## ไฟล์
17:## CTA ที่ยืนยัน
23:## Interaction และ token
29:## หลักฐานตรวจ
33:## สิ่งที่ยังไม่ทำ / ยังไม่ยืนยัน

EXIT 0

CODEX MESSAGE
อัปเดตเอกสารครบแล้ว โดยไม่แตะ `index.html`, `style.css`, `main.js` และไม่ได้รัน server, browser, deploy หรือโมเดลอื่น

- [brief.md](<workspace>/brief.md:10): ยืนยัน Day 1 บท 00–05 / Day 2 บท 06–10, CTA รองไป `#lessons`, และ theme toggle light-default ที่บันทึกเฉพาะ explicit user choice พร้อมตารางปิด GAP เดิม
- [evidence.csv](<workspace>/evidence.csv:14): เพิ่มหลักฐาน D1–D3, ผลตรวจ parent-run 5/5, GAP เรื่อง public deployment และ `STATUS_CHANGE` ที่คงร่องรอย GAP รอบแรก
- [handoff.md](<workspace>/handoff.md:1): สรุปไฟล์, CTA, interaction/token, หลักฐานตรวจ และสิ่งที่ยังไม่ยืนยัน

ผล browser ที่แนบระบุชัดว่า parent runner เป็นผู้รัน Playwright—not this Codex run—ผ่าน 5/5 และยัง `not yet tested in public`; จึงไม่ได้อ้างว่าเผยแพร่แล้ว

ยังไม่อ้างยืนยันผู้สอน, หน่วยกิต, เกณฑ์คะแนน หรือ LMS. ตรวจ CSV แล้วมี 20 records และ 5 คอลัมน์ครบทุกแถว. เมื่อได้ข้อกำหนดใหม่ ต้องปรับ brief, evidence และ implementation ให้สอดคล้องกันเสมอ.

FINAL RESPONSE
อัปเดตเอกสารครบแล้ว โดยไม่แตะ `index.html`, `style.css`, `main.js` และไม่ได้รัน server, browser, deploy หรือโมเดลอื่น

- [brief.md](<workspace>/brief.md:10): ยืนยัน Day 1 บท 00–05 / Day 2 บท 06–10, CTA รองไป `#lessons`, และ theme toggle light-default ที่บันทึกเฉพาะ explicit user choice พร้อมตารางปิด GAP เดิม
- [evidence.csv](<workspace>/evidence.csv:14): เพิ่มหลักฐาน D1–D3, ผลตรวจ parent-run 5/5, GAP เรื่อง public deployment และ `STATUS_CHANGE` ที่คงร่องรอย GAP รอบแรก
- [handoff.md](<workspace>/handoff.md:1): สรุปไฟล์, CTA, interaction/token, หลักฐานตรวจ และสิ่งที่ยังไม่ยืนยัน

ผล browser ที่แนบระบุชัดว่า parent runner เป็นผู้รัน Playwright—not this Codex run—ผ่าน 5/5 และยัง `not yet tested in public`; จึงไม่ได้อ้างว่าเผยแพร่แล้ว

ยังไม่อ้างยืนยันผู้สอน, หน่วยกิต, เกณฑ์คะแนน หรือ LMS. ตรวจ CSV แล้วมี 20 records และ 5 คอลัมน์ครบทุกแถว. เมื่อได้ข้อกำหนดใหม่ ต้องปรับ brief, evidence และ implementation ให้สอดคล้องกันเสมอ.
