/* ============================================================
   site.css — ย้ายจาก inline <style> ใน index.html (~750 บรรทัด)
   ------------------------------------------------------------
   - browser cache repeat visits
   - dev experience: syntax highlight + IDE folding
   - separate concerns จาก HTML structure
   ============================================================ */

/* ── Design tokens ─────────────────────────────────────────
   แก้ palette รอบต่อไปที่นี่ที่เดียว — ใช้อ้างใน .grad, dot-accent,
   underline-grow, pill-accent, และ accent ทุกจุดในไฟล์นี้
   ──────────────────────────────────────────────────────── */
:root {
  --accent-a:      #F97316;   /* orange-500 */
  --accent-b:      #C026D3;   /* fuchsia-600 */
  --ink:           #1c1410;   /* warm near-black — ไม่ pure #000, อิง palette orange */
  --ink-soft:      #52525b;   /* zinc-600  — micro-labels (≥4.5:1 บน surface) */
  --muted:         #71717a;   /* zinc-500  — secondary text (legacy — ใช้เฉพาะ text ≥14px) */
  --surface:       #f9f5f1;   /* warm off-white — page body background */
  --surface-raised:#ffffff;   /* pure white — section cards (pop จาก surface) */
  --border:        #e4e4e7;   /* zinc-200  — section dividers, card borders default */
  --border-strong: #a1a1aa;   /* zinc-400  — emphasis border (hover/focus) */
}

html {
  font-family: 'Inter', 'Noto Sans Thai', 'Sarabun', 'ui-sans-serif', 'system-ui', sans-serif; /* Sarabun: system-font fallback เท่านั้น (ไม่ได้ load จาก Google Fonts แล้ว) */
  /* กัน mobile browser ใช้ scroll anchoring แล้วถูกดึงกลับเมื่อ DOM ของ polaroid เปลี่ยน */
  overflow-anchor: none;
}
/* ────────────────────────────────────────────────────────────────────────
   NOTE: Animations ใน site นี้เปิดเสมอ ไม่ตอบสนอง prefers-reduced-motion
   เพราะเว็บ portfolio = visual design IS the product
   ผู้ออกแบบต้องการให้ทุกผู้ชมเห็น visual language ที่ตั้งใจไว้
   (รวมถึงผู้ที่ตั้งค่า reduce motion ไว้ในระบบ)
   ──────────────────────────────────────────────────────────────────────── */
html { scroll-behavior: smooth; }

body {
  font-family: 'Inter', 'Noto Sans Thai', 'Sarabun', sans-serif !important; /* Sarabun: system fallback */
  background: var(--surface);
  color: var(--ink);
  /* polaroid card ใช้ translateX(±180%) ตอน animate — clip horizontal เพื่อกัน scroll jitter */
  overflow-x: clip;
  /* ปิด scroll-anchor — รูปทุกใบมี aspect-ratio pre-set จาก dimensions.js แล้ว */
  overflow-anchor: none;
  /* (pull-to-refresh เปิดไว้บน mobile — block เฉพาะตอน lightbox open ผ่าน .lb-open) */
  /* Thai-friendly line breaking — break at spaces, ห้ามฉีกกลางคำ
     ถ้าวลีเดียวยาวเกิน container จะ fallback ไป break-word เพื่อกัน overflow */
  word-break: keep-all;
  overflow-wrap: break-word;
  line-break: strict;
}

/* Font inheritance — set บน body แล้วให้ทุก element inherit
   (เลิกใช้ * !important เพื่อเปิดให้ Tailwind font-mono / .font-mono ใช้ JetBrains Mono ได้) */
body, body * {
  font-family: inherit;
}
/* Mono override — JetBrains Mono สำหรับ code/data display */
.font-mono, code, kbd, samp, pre {
  font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace !important;
}

/* No-break: ครอบวลีที่ห้ามแยกบรรทัด เช่น Pre-press, AI-Assisted, ชื่อเฉพาะ */
.nb {
  white-space: nowrap;
}

/* Modern text-wrap (Chrome 114+, Safari 17.4+) — ตัดบรรทัดให้สมดุล/สวยขึ้น */
h1,
h2,
h3 {
  text-wrap: balance;
}

p,
li {
  text-wrap: pretty;
  line-height: 1.8;
}

/* Highlight subtle: ทาเส้นใต้สีไล่ — เน้นโดยไม่กระชาก
   ใช้ color-mix() อ้าง CSS token โดยตรง → เปลี่ยน accent ที่เดียว ไล่สีตาม (Chrome 111+, Firefox 113+, Safari 16.2+) */
.hl {
  background-image: linear-gradient(90deg,
    color-mix(in srgb, var(--accent-a) 22%, transparent),
    color-mix(in srgb, var(--accent-b) 22%, transparent));
  background-repeat: no-repeat;
  background-position: 0 88%;
  background-size: 100% 30%;
  padding: 0 .12em;
}

/* Highlight strong — gradient bg พื้นกว่า hl */
.hl-strong {
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--accent-a) 14%, transparent),
    color-mix(in srgb, var(--accent-b) 18%, transparent));
  padding: .08em .35em;
  border-radius: .25em;
}

.grain::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  opacity: .25;
}

/* Scroll reveal (bidirectional, with stagger via --d) */
.r {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .35s ease, transform .35s ease;
  will-change: opacity, transform;
}

.r.in {
  opacity: 1;
  transform: none;
  transition:
    opacity .9s cubic-bezier(.22, .61, .36, 1) calc(var(--d, 0) * 55ms),
    transform .9s cubic-bezier(.22, .61, .36, 1) calc(var(--d, 0) * 55ms);
}

.r-left {
  transform: translateX(-32px);
}

.r-left.in {
  transform: none;
}

.r-right {
  transform: translateX(32px);
}

.r-right.in {
  transform: none;
}

/* Scroll reveal เปิดเสมอ — เป็น signature transition ของเว็บ */

/* Nav scroll state */
header.scrolled {
  box-shadow: 0 4px 20px -8px rgba(0, 0, 0, .08);
}

/* Gallery initial fade-crop — peek cards render fully, fade to white via mask */
/* Gallery wrapper — height-based crop + mask fade
   ───────────────────────────────────────────────
   Logic: render cards ทุกใบล่วงหน้าใน inner #gallery (JS columns) — เสถียร ไม่ reshuffle
          wrapper คุม visible area ผ่าน max-height + mask fade ที่ขอบล่าง
          ทุก column มี cards extending ใต้ fade เสมอ → fade ต่อเนื่อง ไม่ขาด
   --crop-h        = ความสูงเริ่มต้นที่เห็น (responsive)
   --cap-expansion = multiplier เพิ่มจากการกด "ดูเพิ่มเติม" (1, 2, 4, ...)
*/
.gallery-wrapper {
  --crop-h: 70svh;
  --cap-expansion: 1;
  position: relative;
  transition: max-height 0.5s cubic-bezier(.4, 0, .2, 1);
}
@media (min-width: 768px) {
  .gallery-wrapper { --crop-h: 80svh; }
}
@media (min-width: 1280px) {
  .gallery-wrapper { --crop-h: 85svh; }
}
@supports not (height: 100svh) {
  .gallery-wrapper { --crop-h: 70vh; }
  @media (min-width: 768px) { .gallery-wrapper { --crop-h: 80vh; } }
  @media (min-width: 1280px) { .gallery-wrapper { --crop-h: 85vh; } }
}
.gallery-wrapper.is-cropped {
  /* max-height ตั้งโดย JS แบบ px (เผื่อ browser ไม่ support calc(svh * var)) */
  max-height: var(--crop-h);
  overflow: hidden;
}

/* Sticky fade — ลอยที่ขอบล่าง viewport ตราบที่ gallery-stage ยังอยู่ในจอ
   ทำให้ "fade indicator" ใกล้สายตา user เสมอ ไม่ว่า wrapper จะสูงเท่าไร */
.gallery-stage {
  position: relative;
}
.gallery-fade-bottom {
  position: sticky;
  bottom: 0;
  left: 0;
  right: 0;
  /* เพิ่มจาก 140 → 200 → ramp ยาวขึ้น = สายตาไม่จับ "เส้นจบ" */
  height: 200px;
  margin-top: -200px;
  /* Multi-stop ease-in curve (มี 8 stops จำลอง cubic-bezier) — สมูทกว่า 2-stop linear มาก
     จบที่ #ffffff เป๊ะ ๆ ตรงกับ Works section bg-white → ไม่มีรอยตัด 1% gray
     ไม่ใช้ var(--surface-raised) ใน rgba() (Safari มี bug บาง version) — hardcode 255 */
  background: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0)     0%,
    rgba(255, 255, 255, 0.013) 8%,
    rgba(255, 255, 255, 0.05)  17%,
    rgba(255, 255, 255, 0.13)  27%,
    rgba(255, 255, 255, 0.25)  38%,
    rgba(255, 255, 255, 0.42)  50%,
    rgba(255, 255, 255, 0.62)  63%,
    rgba(255, 255, 255, 0.80)  76%,
    rgba(255, 255, 255, 0.93)  88%,
    rgba(255, 255, 255, 1)     100%
  );
  pointer-events: none;
  z-index: 2;
  opacity: 0;
  transition: opacity 0.3s ease;
}
.gallery-wrapper.is-cropped + .gallery-fade-bottom {
  opacity: 1;
}

/* Mockup placeholder — เติมท้ายคอลัมน์สั้นให้แท่งสูงเท่ากับคอลัมน์สูงสุด
   ทำให้ gallery ดูสมดุล ไม่ขรุขระท้าย; gradient เทาจาง → ขาว ที่ก้นสุด
   ─────────────────────────────────────────────────────────────────────
   ❌ NO BORDER — stroke 1px แม้บางมาก จะวาด "ขอบ card" ทั้ง 4 ด้าน
   ทำให้ตามองเห็นจุดสิ้นสุดของ placeholder ทันที (แม้ fill ไล่ไปขาวแล้ว)
   ✅ KEEP border-radius — กลมกลืนกับ rhythm ของ .work-card (rounded-xl = 0.75rem)
   ── gradient fill จะถูก clip ที่มุมโค้งบน → blend เนียนกับ cards จริงข้างบน */
.mockup-card {
  flex-shrink: 0;
  border-radius: 0.75rem;
  background: linear-gradient(
    to bottom,
    rgba(228, 228, 231, 0.35) 0%,    /* zinc-200 fade in (ลดจาก 0.45 ให้ subtle ขึ้น) */
    rgba(244, 244, 245, 0.18) 45%,   /* zinc-100 mid */
    rgba(255, 255, 255, 0)    100%   /* fade to section bg (white) ไม่ใช่ zinc-50 */
  );
  pointer-events: none;
}

/* Mockup overlay — absolute-positioned ที่ก้น wrapper ในแต่ละ col (cropped state)
   gradient: ใส บน → ขาวเต็มก้น (matched กับ Works section bg-white)
   ใช้ ease-in curve เดียวกับ .gallery-fade-bottom เพื่อให้ overlap ราบรื่น
   ไม่ใช้ zinc-tinted stops อีก — ตอน 2 layer fade ซ้อนกัน zinc tint จะทำให้
   เกิดเงา gray มัวๆ ตรงรอยต่อ (สิ่งที่ user เรียก "จุดตัด") */
.mockup-card.mockup-overlay {
  border: none;
  background: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0)    0%,
    rgba(255, 255, 255, 0.04) 15%,
    rgba(255, 255, 255, 0.14) 30%,
    rgba(255, 255, 255, 0.30) 45%,
    rgba(255, 255, 255, 0.50) 60%,
    rgba(255, 255, 255, 0.72) 75%,
    rgba(255, 255, 255, 0.90) 90%,
    rgba(255, 255, 255, 1)    100%
  );
  z-index: 2;
}
/* Unlocked state — content sees natural height, mask off */
.gallery-wrapper.is-unlocked {
  max-height: none;
  overflow: visible;
}

/* Touch devices ไม่มี hover → แสดง figcaption เป็น subtle persistent gradient
   กัน mobile user พลาด CTA "view all N pages" */
@media (hover: none) {
  .work-card figcaption {
    opacity: 1 !important;
    background: linear-gradient(to top, rgba(0,0,0,0.65) 0%, rgba(0,0,0,0.15) 60%, transparent 100%) !important;
  }
}

.work-card {
  break-inside: avoid;
}

.filter-chip.active {
  background: var(--ink);
  color: var(--surface-raised);
  border-color: var(--ink);
}

.underline-grow {
  position: relative;
}

.underline-grow::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -2px;
  height: 1px;
  width: 0;
  background: currentColor;
  transition: width .3s ease;
}

.underline-grow:hover::after {
  width: 100%;
}

/* Accent gradient text */
.grad {
  background: linear-gradient(90deg, var(--accent-a) 0%, var(--accent-b) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

/* Gradient sphere dots — ไล่สีแบบ 3D ไม่ใช่สีแบน */
.dot-accent {
  background: linear-gradient(90deg, var(--accent-a) 0%, var(--accent-b) 100%);
}

.dot-green {
  background: #22c55e;
  box-shadow: 0 0 0 2.5px #fff, inset 0 1px 2px rgba(0, 0, 0, 0.15);
}

/* Heartbeat — สอง pulse ติดกัน (lub-dub) แล้วเว้น เลียนแบบจังหวะหัวใจคน */
@keyframes heartbeat {
  0%, 28%, 70%, 100% { transform: scale(1); }
  14%, 42%           { transform: scale(1.06); }
}
.heartbeat {
  animation: heartbeat 1.4s ease-in-out infinite;
  transform-origin: center;
  will-change: transform;
}
/* Heartbeat เปิดเสมอ — เป็น cue ของ "Available" ที่จำเป็นต่อ design intent */

/* Tada — attention-grabbing scale + wobble (Animate.css classic)
   ใช้กับ logo + Available button เมื่อ hover */
@keyframes tada {
  from              { transform: scale3d(1, 1, 1); }
  10%, 20%          { transform: scale3d(.9, .9, .9) rotate(-3deg); }
  30%, 50%, 70%, 90% { transform: scale3d(1.1, 1.1, 1.1) rotate(3deg); }
  40%, 60%, 80%     { transform: scale3d(1.1, 1.1, 1.1) rotate(-3deg); }
  to                { transform: scale3d(1, 1, 1); }
}
.animate-tada-hover {
  transform-origin: center;
  /* will-change ไม่ได้ตั้งที่นี่ — JS เพิ่มเฉพาะตอน mouseenter (สำหรับ element ที่ไม่มี .tada-loop)
     .tada-loop มี will-change: transform ของตัวเองอยู่แล้วเพราะ animate ต่อเนื่อง */
}
.animate-tada-hover:hover {
  animation: tada 1s ease-in-out;
}

/* Tada loop — tada 1s + rest 7s รวม 8s/cycle (motion อยู่ใน 12.5% แรกของ cycle)
   ใช้กับ "Available" badge — เด่นแบบไม่รำคาญ */
@keyframes tada-loop {
  0%, 12.5%, 100%             { transform: scale3d(1, 1, 1); }
  1.25%, 2.5%                 { transform: scale3d(.9, .9, .9) rotate(-3deg); }
  3.75%, 6.25%, 8.75%, 11.25% { transform: scale3d(1.1, 1.1, 1.1) rotate(3deg); }
  5%, 7.5%, 10%               { transform: scale3d(1.1, 1.1, 1.1) rotate(-3deg); }
}
.tada-loop {
  animation: tada-loop 8s ease-in-out infinite;
  transform-origin: center;
  will-change: transform;
}
/* บน element ที่มีทั้ง tada-loop + animate-tada-hover → hover override ด้วย tada 1s
   เร็วและตอบสนองทันที, ปล่อย hover → tada-loop กลับมาต่อ */
.tada-loop.animate-tada-hover:hover {
  animation: tada 1s ease-in-out;
}

/* Dot-live — subtle opacity pulse สำหรับ status dots (เช่น hero "Open to work" + contact "Available for work")
   เด่นพอจะเป็น "live indicator" แต่ไม่แย่ง attention จาก tada-loop ของ nav Available */
@keyframes dot-live-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}
.dot-live {
  animation: dot-live-pulse 2.4s ease-in-out infinite;
}

/* Circle bullet สำหรับ experience list — สีเดียวกับ text เพื่อลดความเด่น
   margin-top ใช้ em → scale ตาม font-size auto + จัดให้ตรงกลางบรรทัดแรกของข้อความ */
.dot-bullet {
  flex-shrink: 0;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.55;
  margin-top: 0.78em;
}

/* Pill ไล่สีสำหรับชื่อบริษัท + จังหวัด ใน experience */
.pill-accent {
  background: linear-gradient(90deg, var(--accent-a) 0%, var(--accent-b) 100%);
}

/* Latin-cap balance — ลด font-size ของ Latin run ใน element ที่ผสมไทย
   เพื่อให้ cap-height ของ Latin (Inter ~0.73em) ใกล้ Thai consonant body (~0.55em)
   baseline ยัง align กันอัตโนมัติ (inline element baseline rule) */
.latin-cap {
  font-size: 0.78em;
  /* ไม่ใส่ line-height — ใช้ inherit เพื่อกัน line shift */
}

/* Fix Inter Black subpixel notch บน heavy-weight headings */
section h2 {
  text-rendering: geometricPrecision;
}

/* ============ Micro-interactions ============ */

/* Scroll progress bar — แถบไล่สีบนสุด แสดง % เลื่อน
   ใช้ transform: scaleX() แทน width — compositable, ไม่ trigger layout paint
   JS ตั้งค่า scaleX(0–1) ตาม scroll progress */
.scroll-progress {
  position: fixed;
  top: 0; left: 0;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  background: linear-gradient(90deg, #F97316 0%, #C026D3 100%);
  z-index: 100;
  pointer-events: none;
  will-change: transform;
}

/* Section number label (01, 02...) — letter-spacing เปิดเมื่อ hover */
.sec-label {
  transition: letter-spacing .35s cubic-bezier(.4,0,.2,1), color .3s ease;
  display: inline-block;
}
.sec-label:hover {
  letter-spacing: .42em;
  color: var(--ink);
}

/* Skill card — icon wiggle ใช้ tailwindcss-animated group-hover:animate-wiggle
   transform-origin เพื่อให้ wiggle หมุนจากจุดกึ่งกลาง */
.skill-icon-wrap {
  transform-origin: center;
}

/* Filter chip — ลอยขึ้นเล็กน้อยเมื่อ hover (เฉพาะตัวที่ยังไม่ active) */
.filter-chip {
  transition: transform .2s ease, border-color .2s ease, background .2s ease, color .2s ease;
}
.filter-chip:hover:not(.active) {
  transform: translateY(-2px);
}

/* CTA arrow — ลูกศรเคลื่อนทแยงเมื่อ hover ปุ่ม */
.cta-arrow {
  transition: transform .35s cubic-bezier(.34,1.56,.64,1);
}
.group:hover .cta-arrow {
  transform: translate(3px, -3px);
}

/* TON. logo dot — หมุน 180° เมื่อ hover logo */
.logo-dot {
  display: inline-block;
  transition: transform .5s cubic-bezier(.34,1.56,.64,1);
  transform-origin: 50% 65%;
}
a:hover > .logo-dot,
a:hover .logo-dot {
  transform: rotate(180deg) scale(1.2);
}

/* Footer cat — กระดิกเมื่อ hover */
@keyframes cat-wiggle {
  0%, 100% { transform: rotate(0); }
  15% { transform: rotate(-14deg); }
  30% { transform: rotate(10deg); }
  45% { transform: rotate(-7deg); }
  60% { transform: rotate(5deg); }
  75% { transform: rotate(-2deg); }
}
.footer-cat {
  display: inline-block;
  transform-origin: 50% 80%;
  transition: transform .2s ease;
}
.footer-cat:hover {
  animation: cat-wiggle .7s ease-in-out;
}

/* Stat number — ลอยขึ้นเมื่อ hover ตัวเลข */
.stat-num-wrap {
  display: inline-block;
  transition: transform .35s cubic-bezier(.34,1.56,.64,1);
  transform-origin: bottom left;
}
.stat-num-wrap:hover {
  transform: translateY(-4px) scale(1.04);
}

/* Nav link gradient underline-grow — ใช้สี gradient แทน solid */
.underline-grow.grad-line::after {
  background: linear-gradient(90deg, var(--accent-a) 0%, var(--accent-b) 100%);
  height: 2px;
}

/* Micro-interactions เปิดเสมอ — ทุกอันเป็น part of design language */

/* ============ Hero — Letter stagger + WUTHICHAI gradient sweep ============ */

/* Letter stagger reveal — ใช้กับทุกตัวที่ split ใน TON + WUTHICHAI
   --i คือ index ตัวอักษร ใช้คำนวณ animation-delay ตามลำดับ */
.hero-letter {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.5em);
  animation: hero-letter-in .7s cubic-bezier(.22,.61,.36,1) forwards;
  animation-delay: calc(var(--i, 0) * 50ms);
  will-change: opacity, transform;
}
@keyframes hero-letter-in {
  to { opacity: 1; transform: translateY(0); }
}

/* WUTHICHAI — single span (รักษา letter-spacing เดิม ไม่แตก)
   reveal: clip-path wipe ซ้าย→ขวา
   hover: radial gradient ตามเคอร์เซอร์
   layered bg — radial (alpha ปรับได้) ทับ linear gray:
     enter: radius พองจาก cursor + alpha 0→1
     leave: radius FREEZE ที่ขนาดปัจจุบัน + alpha 1→0 (สีจางหายโดยรูปทรงคง) */
#hero-wuthichai {
  position: relative;
  display: inline-block;
  color: transparent;
  background:
    radial-gradient(
      circle var(--rad, 0px) at var(--mx, 50%) var(--my, 50%),
      rgba(249, 115, 22, var(--alpha, 0)) 0%,
      rgba(192, 38, 211, var(--alpha, 0)) 28%,
      rgba(192, 38, 211, 0) 70%
    ),
    linear-gradient(#a1a1aa, #a1a1aa);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  clip-path: inset(0 100% 0 0);
  animation: wuth-wipe 1s cubic-bezier(.22,.61,.36,1) forwards;
  animation-delay: 250ms;
  will-change: clip-path;
}
@keyframes wuth-wipe {
  to { clip-path: inset(0 0 0 0); }
}

/* Hero letter stagger + WUTHICHAI sweep เปิดเสมอ — เป็น signature ของหน้า */

/* ============ View Transitions API — gallery card ↔ lightbox image ============ */
/* ทำงานบน browser ที่รองรับ document.startViewTransition (Chrome 111+, Safari 18+, Edge 111+)
   browser อื่นจะ fallback ไป normal open/close โดยไม่มี morph */

/* Default ทุก transition ของหน้านี้ */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.35s;
  animation-timing-function: cubic-bezier(.4, 0, .2, 1);
}

/* Specific morph สำหรับรูปงาน (gallery thumbnail → lightbox full image) */
::view-transition-group(work-cover) {
  animation-duration: 0.55s;
  animation-timing-function: cubic-bezier(.4, 0, .2, 1);
}
::view-transition-image-pair(work-cover) {
  isolation: auto;
}
::view-transition-old(work-cover),
::view-transition-new(work-cover) {
  /* ทับซ้อนกัน ไม่ cross-fade ทำให้ morph สมูทกว่า */
  animation: none;
  mix-blend-mode: normal;
  height: 100%;
  object-fit: cover;
}

/* ============ CTA gradient — Get in touch button ============ */
/* Default: bg-black solid / hover: gradient ผ่าน ::before + shimmer ไหลตลอด
   ใช้ isolation:isolate + ::before z-index:0 ให้ gradient ทับ black แต่ใต้ text */
.cta-grad {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}
.cta-grad::before {
  content: '';
  position: absolute;
  inset: 0;
  /* Seamless loop — start และ end เป็นสีเดียวกัน (orange)
     pattern: orange → purple → orange ใน 200% width
     เคลื่อน -200% = แสดงครบหนึ่ง pattern พอดี กลับมาที่จุดเดิม ไม่มีรอยต่อ */
  background: linear-gradient(120deg,
    #F97316 0%,
    #C026D3 50%,
    #F97316 100%);
  background-size: 200% 100%;
  background-position: 0% 0;
  opacity: 0;
  z-index: 0;
  border-radius: inherit;
  transition: opacity .4s cubic-bezier(.22,.61,.36,1);
  will-change: opacity, background-position;
}
.group:hover .cta-grad::before {
  opacity: 1;
  animation: cta-shimmer 4s linear infinite;
}
@keyframes cta-shimmer {
  from { background-position: 0% 0; }
  to   { background-position: -200% 0; }
}
/* CTA gradient sweep เปิดเสมอ */

/* ============ Custom cursor — dot เล็ก + ขยาย+ดูดเมื่อใกล้ .magnetic ============ */
/* ใช้เฉพาะอุปกรณ์ pointer:fine + ไม่อยู่ใน reduced-motion mode
   ซ่อน default cursor แล้วใช้ custom แทน — JS lerp transform ตลอด */
@media (pointer: fine) {
  body.has-custom-cursor,
  body.has-custom-cursor a,
  body.has-custom-cursor button,
  body.has-custom-cursor input,
  body.has-custom-cursor [role="button"] {
    cursor: none;
  }
}
.custom-cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  /* สีขาวล้วน + mix-blend-mode: difference
     → render เป็นสีตรงข้ามของ background ทุกพื้น = เห็นชัดทั้งจอสว่างและมืด
     (บน #fafafa เป็นเกือบดำ, บนพื้นดำเป็นขาว, บน purple เป็นเขียว ฯลฯ) */
  background: #ffffff;
  border: 0 solid transparent;
  pointer-events: none;
  z-index: 9999;
  transform: translate(-100px, -100px);
  mix-blend-mode: difference;
  transition:
    width  .35s cubic-bezier(.34, 1.56, .64, 1),
    height .35s cubic-bezier(.34, 1.56, .64, 1),
    background .3s ease,
    border .3s ease,
    mix-blend-mode 0s linear .15s;
  will-change: transform;
}
/* State: ใกล้/อยู่บน clickable — วงขยายใหญ่ + เส้นรอบไล่สี orange→purple
   Trick: linear-gradient เต็มกรอบ + radial-gradient mask เจาะกลาง = เหลือเฉพาะวงขอบหนา 4.5px */
.custom-cursor.near-cta {
  width: 54px;
  height: 54px;
  background: linear-gradient(135deg, #F97316 0%, #C026D3 100%);
  border: 0;
  -webkit-mask: radial-gradient(circle closest-side, transparent calc(100% - 2.5px), #000 calc(100% - 1.5px));
          mask: radial-gradient(circle closest-side, transparent calc(100% - 2.5px), #000 calc(100% - 1.5px));
  mix-blend-mode: normal;
  transition:
    width  .4s cubic-bezier(.34, 1.56, .64, 1),
    height .4s cubic-bezier(.34, 1.56, .64, 1),
    background .25s ease;
}

/* Hide บนมือถือ touch devices เท่านั้น (custom cursor ไม่จำเป็นถ้าไม่มี mouse) */
@media (pointer: coarse) {
  .custom-cursor { display: none !important; }
}

/* ============ Magnetic — elements ที่ดึงเข้าหา cursor ============ */
/* JS lerp transform บน element นี้ — ไม่ใช้ CSS transition (จะชนกัน)
   ใส่ contain เพื่อกัน layout shift จาก translate */
.magnetic {
  display: inline-flex;
  will-change: transform;
  contain: layout;
}

/* Grid background */
.grid-bg {
  background-image:
    linear-gradient(rgba(0, 0, 0, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0, 0, 0, 0.045) 1px, transparent 1px);
  background-size: 40px 40px;
}

/* Lightbox */
.lb-open {
  overflow: hidden;
  /* block pull-to-refresh + scroll chaining เฉพาะตอน lightbox open */
  overscroll-behavior-y: contain;
}

/* Polaroid stack */
.polaroid {
  background: #fdfcf9;
  padding: 12px 12px 42px 12px;
  box-shadow: 0 20px 35px rgba(0, 0, 0, .15), 0 6px 12px rgba(0, 0, 0, .08);
  border-radius: 3px;
  position: absolute;
  width: 220px;
}

@media (min-width: 640px) {
  .polaroid {
    width: 280px;
    padding: 14px 14px 50px 14px;
  }
}

.polaroid::after {
  content: "";
  position: absolute;
  top: -10px;
  left: 50%;
  width: 90px;
  height: 26px;
  transform: translateX(-50%) rotate(-3deg);
  background: rgba(252, 211, 77, 0.55);
  background-image: linear-gradient(90deg, rgba(0, 0, 0, .04) 0, rgba(0, 0, 0, 0) 8px, rgba(0, 0, 0, 0) calc(100% - 8px), rgba(0, 0, 0, .04) 100%);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .06);
}

.polaroid .img-frame {
  width: 100%;
  aspect-ratio: 1/1.05;
}

.polaroid .img-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.polaroid-stack {
  position: relative;
  height: 460px;
  perspective: 1000px;
  /* ปิด scroll-anchor เพื่อกัน mobile scroll กระตุก ตอน card หมุนเปลี่ยน */
  overflow-anchor: none;
  /* CSS containment — แยก layout/style ของ stack ออกจาก document
     (ไม่ใส่ paint — paint จะ clip card ที่บินออก ทำให้เห็นขอบตัดก่อน fade) */
  contain: layout style;
}

@media (min-width: 768px) {
  .polaroid-stack {
    height: 520px;
  }
}

.polaroid-card {
  transition: transform .6s cubic-bezier(.4, .0, .2, 1), opacity .5s ease;
  will-change: transform, opacity;
}

.polaroid-card[data-pos="back"] {
  transform: translate(-50%, -50%) rotate(-8deg) translateX(-90px) translateY(20px) scale(.92);
  z-index: 1;
  opacity: .65;
  top: 50%;
  left: 50%;
}

.polaroid-card[data-pos="mid"] {
  transform: translate(-50%, -50%) rotate(5deg) translateX(60px) translateY(-10px) scale(.97);
  z-index: 2;
  opacity: .85;
  top: 50%;
  left: 50%;
}

.polaroid-card[data-pos="front"] {
  transform: translate(-50%, -50%) rotate(-2deg);
  z-index: 3;
  opacity: 1;
  top: 50%;
  left: 50%;
}

.polaroid-card[data-pos="out"] {
  transform: translate(-50%, -50%) rotate(-25deg) translateX(-180%) translateY(-40px);
  z-index: 0;
  opacity: 0;
  top: 50%;
  left: 50%;
  pointer-events: none;
}

/* Mirror ของ out + in — สำหรับทิศย้อนกลับ (กดด้านซ้าย) */
.polaroid-card[data-pos="out-right"] {
  transform: translate(-50%, -50%) rotate(25deg) translateX(180%) translateY(-40px);
  z-index: 0;
  opacity: 0;
  pointer-events: none;
}

.polaroid-card[data-pos="in-left"] {
  transform: translate(-50%, -50%) rotate(-12deg) translateX(-180%) translateY(-40px) scale(.85);
  z-index: 0;
  opacity: 0;
  pointer-events: none;
}

.polaroid-card[data-pos="in"] {
  transform: translate(-50%, -50%) rotate(12deg) translateX(180%) translateY(-40px) scale(.85);
  z-index: 0;
  opacity: 0;
  top: 50%;
  left: 50%;
}

/* Skeleton loading + image fade-in */
.skel {
  position: relative;
  background: #f4f4f5;
  overflow: hidden;
  isolation: isolate;
  /* contain child z-index */
}

.skel::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.55) 50%, transparent 100%);
  background-size: 200% 100%;
  animation: skel-shimmer 1.4s ease-in-out infinite;
  z-index: 1;
  pointer-events: none;
}

.skel>img:not(.eye-sprite) {
  opacity: 0;
  /* transition ทั้ง opacity (สำหรับ fade-in) และ transform (hover scale) — ห้ามใช้ shorthand override */
  transition: opacity .5s ease, transform .5s cubic-bezier(.4, 0, .2, 1);
  position: relative;
  z-index: 2;
}

.skel.loaded::before {
  display: none;
}

.skel.loaded>img:not(.eye-sprite) {
  opacity: 1;
}

@keyframes skel-shimmer {
  0% {
    background-position: 200% 0;
  }

  100% {
    background-position: -200% 0;
  }
}

/* Light copy protection — เฉพาะรูปงานในแกลเลอรี/ไลท์บ็อกซ์/สไลด์โชว์/hero
   กัน casual users คัดลอก/ลาก/long-press save — ไม่กระทบรูปอื่น เช่น ไอคอน, sprite */
#gallery img,
#lightbox img,
#polaroid-stack img,
#hero-photo,
#hero-photo-bg {
  -webkit-user-drag: none;
  -webkit-touch-callout: none;
  user-select: none;
  -webkit-user-select: none;
}

/* Eye-sprite layers — รูปตามองทิศต่างๆ swap ทีละตัว ไม่ blend (กัน blur) */
.eye-sprite {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  /* สั้นพอให้ฟีลกระชับ ไม่ค้าง 2 รูปทับกัน */
  transition: opacity .1s ease-out;
  pointer-events: none;
  z-index: 3;
}

/* Eye sprites ใช้กับ desktop เท่านั้น (touch ไม่มี cursor) — แต่เปิดเสมอใน desktop */
@media (pointer: coarse) {
  .eye-sprite {
    display: none;
  }
}

/* ── Tinted neutrals — pure #000 / #18181b → var(--ink) ────────────────────
   Override Tailwind bg-black / hover:bg-black บน interactive elements
   ให้สอดคล้องกับ warm near-black ใน --ink palette
   ──────────────────────────────────────────────────────────────────────── */

/* CTA "Get in touch" base button */
.cta-grad {
  background-color: var(--ink);
}

/* CTA arrow circle + load-more + filter active: hover → warm near-black */
.group:hover .group-hover\:bg-black,
.hover\:bg-black:hover {
  background-color: var(--ink);
}

/* Lightbox active filter option (mobile listbox) */
#filter-menu .filter-opt.bg-zinc-900 {
  background-color: var(--ink);
}

/* ── Gallery card focus parity ──────────────────────────────────────────────
   hover overlay (figcaption) ปกติใช้ group-hover — เพิ่ม focus-within ให้
   keyboard users เห็น title/category เหมือน hover (ไม่ต้องแก้ HTML / rebuild CSS)
   ──────────────────────────────────────────────────────────────────────── */
.work-card:focus-within figcaption,
.work-card:focus figcaption {
  opacity: 1;
}

/* ── Token utilities — bridge สำหรับแทนที่ Tailwind zinc/white literals ทีละรอบ ──────
   เพิ่มแทนที่ bg-white / text-zinc-500 / text-zinc-900 ทีละจุดโดยไม่ต้อง rebuild CSS
   ใช้คู่กับ Tailwind: class="bg-surface" แทน bg-zinc-50 ฯลฯ
   ──────────────────────────────────────────────────────────────────────────────────── */
.text-ink          { color: var(--ink); }
.text-ink-soft     { color: var(--ink-soft); }
.text-muted        { color: var(--muted); }
.bg-surface        { background-color: var(--surface); }
.bg-surface-raised { background-color: var(--surface-raised); }
.border-token        { border-color: var(--border); }
.border-token-strong { border-color: var(--border-strong); }

/* ── sr-only — utility ใหม่ ใช้กับ <h3> ใน gallery card เพื่อ SR heading nav ──────
   Tailwind's built-in sr-only ไม่ถูก include เพราะ scan static HTML/JS เท่านั้น
   เลย shadow ใน CSS เพื่อให้ใช้กับ HTML ที่ inject จาก JS ได้ (P3-1)
   ──────────────────────────────────────────────────────────────────────────── */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── P2-2: Token-based migrations (apply ให้เห็นผลทันที โดยไม่ต้องแตะ HTML) ──────
   selector ที่ uniquely identify ใน HTML ตอนนี้ → override สี/border ด้วย CSS var
   วิธีนี้ทำให้ rebrand รอบหน้าแก้แค่ :root tokens 1 ที่ ไม่ต้องไล่ Tailwind class
   ──────────────────────────────────────────────────────────────────────────── */

/* Work card border → token (กัน rebuild Tailwind ทุกครั้งที่ token เปลี่ยน) */
.work-card { border-color: var(--border); }
.work-card:hover { border-color: var(--border-strong); }

/* Filter chip default border → token */
.filter-chip { border-color: var(--border); }
.filter-chip:hover:not(.active) { border-color: var(--ink); }

/* Polaroid background → token (was #fdfcf9 hardcoded — เก็บ warm cast แต่อิง surface) */
.polaroid { background: color-mix(in srgb, var(--surface-raised) 92%, var(--accent-a) 4%); }

/* ── P2-6: Custom cursor visibility fallback ──────────────────────────────────
   mix-blend-mode: difference อาจหายตอนผ่านพื้นสี mid-gray (#808080 area)
   เพิ่ม subtle drop-shadow เป็น contrast halo — กรณี blend หายก็ยังเห็นเงา
   ──────────────────────────────────────────────────────────────────────────── */
.custom-cursor {
  filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.35)) drop-shadow(0 0 2px rgba(255, 255, 255, 0.25));
}
/* near-cta state — มี gradient ring ของตัวเองแล้ว ไม่ต้อง halo เสริม */
.custom-cursor.near-cta {
  filter: none;
}
