/* =====================================================================
   Sentinel — ระบบภาพของคอนโซลฝั่งนักวิจัย
   ---------------------------------------------------------------------
   แนวคิด: นี่คือแผงควบคุม ไม่ใช่เว็บไซต์ — ต้องอ่านสถานะได้เร็วกว่าสวย
   · สีบอกความหมายเสมอ (ระดับความรุนแรง/สถานะ) ไม่ใช่เพื่อตกแต่ง
   · ตัวเลขทุกที่ใช้ตัวเลขความกว้างเท่ากัน เพื่อให้เทียบคอลัมน์ได้
   · รหัส/ตัวระบุใช้ฟอนต์ monospace เพื่อให้แยกจากข้อความปกติ
   ===================================================================== */

/* ---------- โทเคนสี: สว่าง ---------- */
/* =====================================================================
   โทเคนสี — สร้างจากค่าเฉดสีตัวเดียว
   ---------------------------------------------------------------------
   ทุกสีในหน้าเกิดจาก --h (เฉดสี) กับ --cs (ตัวคูณความอิ่มสี)
   เขียนด้วย oklch เพราะความสว่างของมันตรงกับที่ตาเห็นจริง — เปลี่ยนเฉดสี
   จากเขียวเป็นม่วงแล้วความสว่างไม่กระโดด ถ้าใช้ hsl สีเหลืองจะสว่างจ้า
   ส่วนสีน้ำเงินจะมืดจนอ่านไม่ออกทั้งที่ตัวเลข L เท่ากัน

   สีระดับความรุนแรง (ok/warn/high/crit) ตรึงไว้ ไม่เปลี่ยนตามธีม —
   สีเตือนภัยต้องหมายถึงสิ่งเดียวกันเสมอ ไม่ว่าใครตั้งธีมเป็นอะไร
   ===================================================================== */
:root {
  --h: 183;   /* เขียวมรกต — ค่าตั้งต้น */
  --cs: 1;    /* ตัวคูณความอิ่มสี */

  /* บอกเบราว์เซอร์ว่าหน้านี้โทนไหน คอนโทรลพื้นฐาน (ช่องติ๊ก สกรอลบาร์ ป๊อปอัป select)
     จะได้ใช้ชุดสีให้ตรงกัน ไม่งั้นโหมดมืดจะได้ช่องติ๊กสีขาวโพลนกลางฟอร์ม */
  color-scheme: light;

  --bg:            oklch(96.7% calc(.005 * var(--cs)) var(--h));
  --surface:       oklch(100%  0 var(--h));
  --surface-2:     oklch(98.2% calc(.004 * var(--cs)) var(--h));
  --surface-sunk:  oklch(95.8% calc(.005 * var(--cs)) var(--h));
  --border:        oklch(91.9% calc(.008 * var(--cs)) var(--h));
  --border-strong: oklch(85.6% calc(.011 * var(--cs)) var(--h));
  --text:          oklch(20.6% calc(.016 * var(--cs)) var(--h));
  --text-2:        oklch(44.0% calc(.019 * var(--cs)) var(--h));
  --text-3:        oklch(62.0% calc(.019 * var(--cs)) var(--h));

  --accent:        oklch(47.7% calc(.080 * var(--cs)) var(--h));
  --accent-hover:  oklch(40.3% calc(.067 * var(--cs)) var(--h));
  --accent-soft:   oklch(94.4% calc(.016 * var(--cs)) var(--h));
  --accent-ring:   oklch(47.7% calc(.080 * var(--cs)) var(--h) / .28);
  /* สีตัวอักษรบนพื้น accent — โหมดสว่างพื้นเข้มพอให้ใช้ขาวได้ */
  --accent-ink:    oklch(100% 0 var(--h));

  --nav-bg:        oklch(22.9% calc(.022 * var(--cs)) var(--h));
  --nav-text:      oklch(87.7% calc(.015 * var(--cs)) var(--h));
  --nav-text-dim:  oklch(63.9% calc(.025 * var(--cs)) var(--h));
  --nav-active:    oklch(34.1% calc(.047 * var(--cs)) var(--h));
  --nav-border:    oklch(29.9% calc(.027 * var(--cs)) var(--h));
  --nav-accent:    oklch(74.5% calc(.104 * var(--cs)) var(--h));

  --ok:     #1e9e5a;  --ok-soft:    #e3f5ea;
  --warn:   #d68910;  --warn-soft:  #fdf1dd;
  --high:   #d9701f;  --high-soft:  #fdeade;
  --crit:   #d63c2c;  --crit-soft:  #fce6e3;
  --info:   #2a72b5;  --info-soft:  #e5eff8;

  --shadow-sm: 0 1px 2px rgba(15,26,24,.05);
  --shadow:    0 1px 3px rgba(15,26,24,.07), 0 6px 16px -10px rgba(15,26,24,.28);
  --shadow-lg: 0 2px 6px rgba(15,26,24,.08), 0 18px 40px -22px rgba(15,26,24,.45);

  --r-sm: 5px;  --r: 8px;  --r-lg: 12px;

  /* ระยะห่างและขนาดปรับตามความหนาแน่นที่ผู้ใช้เลือก */
  --pad-y:  10px;
  --pad-y-sm: 7px;
  --row-y:  11px;
  --gap:    18px;

  --font-display: "Bai Jamjuree", var(--font-body), sans-serif;
  --font-body:    "IBM Plex Sans Thai", -apple-system, "Segoe UI", sans-serif;
  --font-mono:    "IBM Plex Mono", "SFMono-Regular", Menlo, monospace;
  --fs: 1;
}

/* ---------- ชุดสีให้เลือก — กำหนดแค่เฉดสี ที่เหลือคำนวณต่อเอง ---------- */
:root[data-accent="teal"]    { --h: 183; --cs: 1;    }
:root[data-accent="green"]   { --h: 148; --cs: 1;    }
:root[data-accent="blue"]    { --h: 248; --cs: 1.05; }
:root[data-accent="indigo"]  { --h: 276; --cs: 1.05; }
:root[data-accent="violet"]  { --h: 305; --cs: 1;    }
:root[data-accent="pink"]    { --h: 352; --cs: 1;    }
:root[data-accent="red"]     { --h:  27; --cs: 1;    }
:root[data-accent="orange"]  { --h:  55; --cs: 1.12; }
:root[data-accent="gold"]    { --h:  90; --cs: 1.25; }
:root[data-accent="slate"]   { --h: 250; --cs: .28;  }

/* ---------- โทเคนสี: มืด ---------- */
/* ค่าเดียวกันสองที่โดยตั้งใจ — ชุดบนคือ "ตามระบบ" ชุดล่างคือผู้ใช้เลือกมืดเอง
   ต้องแยกกันเพราะผู้ใช้ที่เครื่องตั้งสว่างแต่เลือกมืด ต้องได้มืด */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg:            oklch(17.5% calc(.011 * var(--cs)) var(--h));
    --surface:       oklch(21.7% calc(.013 * var(--cs)) var(--h));
    --surface-2:     oklch(24.2% calc(.014 * var(--cs)) var(--h));
    --surface-sunk:  oklch(19.5% calc(.013 * var(--cs)) var(--h));
    --border:        oklch(30.1% calc(.018 * var(--cs)) var(--h));
    --border-strong: oklch(36.8% calc(.022 * var(--cs)) var(--h));
    --text:          oklch(93.3% calc(.009 * var(--cs)) var(--h));
    --text-2:        oklch(77.0% calc(.018 * var(--cs)) var(--h));
    --text-3:        oklch(59.9% calc(.020 * var(--cs)) var(--h));

    --accent:        oklch(73.2% calc(.111 * var(--cs)) var(--h));
    --accent-hover:  oklch(80.8% calc(.103 * var(--cs)) var(--h));
    --accent-soft:   oklch(29.3% calc(.038 * var(--cs)) var(--h));
    --accent-ring:   oklch(73.2% calc(.111 * var(--cs)) var(--h) / .32);
    /* โหมดมืด accent สว่าง — ตัวอักษรขาวบนพื้นนี้อ่านไม่ออก ต้องใช้สีเข้ม */
    --accent-ink:    oklch(17% calc(.02 * var(--cs)) var(--h));

    --nav-bg:        oklch(17.4% calc(.012 * var(--cs)) var(--h));
    --nav-text:      oklch(82.2% calc(.019 * var(--cs)) var(--h));
    --nav-text-dim:  oklch(57.3% calc(.024 * var(--cs)) var(--h));
    --nav-active:    oklch(29.7% calc(.036 * var(--cs)) var(--h));
    --nav-border:    oklch(26.0% calc(.018 * var(--cs)) var(--h));
    --nav-accent:    oklch(74.5% calc(.104 * var(--cs)) var(--h));

    --ok:   #35c07a;  --ok-soft:   #10291d;
    --warn: #e5a53a;  --warn-soft: #2c2211;
    --high: #ef8b45;  --high-soft: #2e1e11;
    --crit: #f2685a;  --crit-soft: #301613;
    --info: #5a9fdc;  --info-soft: #10202e;

    --shadow-sm: 0 1px 2px rgba(0,0,0,.4);
    --shadow:    0 1px 3px rgba(0,0,0,.5), 0 8px 20px -12px rgba(0,0,0,.85);
    --shadow-lg: 0 2px 8px rgba(0,0,0,.55), 0 20px 44px -24px rgba(0,0,0,.95);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg:            oklch(17.5% calc(.011 * var(--cs)) var(--h));
  --surface:       oklch(21.7% calc(.013 * var(--cs)) var(--h));
  --surface-2:     oklch(24.2% calc(.014 * var(--cs)) var(--h));
  --surface-sunk:  oklch(19.5% calc(.013 * var(--cs)) var(--h));
  --border:        oklch(30.1% calc(.018 * var(--cs)) var(--h));
  --border-strong: oklch(36.8% calc(.022 * var(--cs)) var(--h));
  --text:          oklch(93.3% calc(.009 * var(--cs)) var(--h));
  --text-2:        oklch(77.0% calc(.018 * var(--cs)) var(--h));
  --text-3:        oklch(59.9% calc(.020 * var(--cs)) var(--h));

  --accent:        oklch(73.2% calc(.111 * var(--cs)) var(--h));
  --accent-hover:  oklch(80.8% calc(.103 * var(--cs)) var(--h));
  --accent-soft:   oklch(29.3% calc(.038 * var(--cs)) var(--h));
  --accent-ring:   oklch(73.2% calc(.111 * var(--cs)) var(--h) / .32);
  --accent-ink:    oklch(17% calc(.02 * var(--cs)) var(--h));

  --nav-bg:        oklch(17.4% calc(.012 * var(--cs)) var(--h));
  --nav-text:      oklch(82.2% calc(.019 * var(--cs)) var(--h));
  --nav-text-dim:  oklch(57.3% calc(.024 * var(--cs)) var(--h));
  --nav-active:    oklch(29.7% calc(.036 * var(--cs)) var(--h));
  --nav-border:    oklch(26.0% calc(.018 * var(--cs)) var(--h));
  --nav-accent:    oklch(74.5% calc(.104 * var(--cs)) var(--h));

  --ok:   #35c07a;  --ok-soft:   #10291d;
  --warn: #e5a53a;  --warn-soft: #2c2211;
  --high: #ef8b45;  --high-soft: #2e1e11;
  --crit: #f2685a;  --crit-soft: #301613;
  --info: #5a9fdc;  --info-soft: #10202e;

  --shadow-sm: 0 1px 2px rgba(0,0,0,.4);
  --shadow:    0 1px 3px rgba(0,0,0,.5), 0 8px 20px -12px rgba(0,0,0,.85);
  --shadow-lg: 0 2px 8px rgba(0,0,0,.55), 0 20px 44px -24px rgba(0,0,0,.95);
}

/* ---------- แบบอักษรที่ผู้ใช้เลือก ---------- */
:root[data-font="plex"]           { --font-body: "IBM Plex Sans Thai", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="noto"]           { --font-body: "Noto Sans Thai", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="sarabun"]        { --font-body: "Sarabun", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="anuphan"]        { --font-body: "Anuphan", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="niramit"]        { --font-body: "Niramit", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="krub"]           { --font-body: "Krub", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="athiti"]         { --font-body: "Athiti", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="ibmthai"]        { --font-body: "IBM Plex Sans Thai Looped", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="googlesans"]     { --font-body: "Google Sans", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="kanit"]          { --font-body: "Kanit", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="prompt"]         { --font-body: "Prompt", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="bai"]            { --font-body: "Bai Jamjuree", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="chakra"]         { --font-body: "Chakra Petch", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="mitr"]           { --font-body: "Mitr", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="k2d"]            { --font-body: "K2D", -apple-system, "Segoe UI", sans-serif; }
:root[data-font="notoserif"]      { --font-body: "Noto Serif Thai", "Noto Serif Thai", Georgia, serif; }
:root[data-font="taviraj"]        { --font-body: "Taviraj", "Noto Serif Thai", Georgia, serif; }
:root[data-font="trirong"]        { --font-body: "Trirong", "Noto Serif Thai", Georgia, serif; }
:root[data-font="maitree"]        { --font-body: "Maitree", "Noto Serif Thai", Georgia, serif; }
:root[data-font="pridi"]          { --font-body: "Pridi", "Noto Serif Thai", Georgia, serif; }

:root[data-density="compact"] {
  --pad-y: 7px; --pad-y-sm: 5px; --row-y: 7px; --gap: 13px;
}

/* ---------- พื้นฐาน ---------- */
* { box-sizing: border-box; }
html { font-size: calc(16px * var(--fs)); }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font-family: var(--font-body); font-size: .94rem; line-height: 1.65;
  -webkit-font-smoothing: antialiased; font-variant-numeric: tabular-nums;
}
a { color: var(--accent); text-decoration: none; text-underline-offset: 3px; }

/* ไอคอนต้องมีขนาดคงที่เสมอ ไม่งั้น SVG จะขยายเต็มกล่องที่มันอยู่ */
/* ไอคอน Flaticon เป็นฟอนต์ ต้องจัดขนาด/ระยะเอง ไม่งั้นบรรทัดจะเบี้ยว
   line-height:0 คือกุญแจ — ฟอนต์ไอคอนพก line-height ของตัวเองมาด้วย */
i.fi.ic, svg.ic { width: 16px; height: 16px; flex: 0 0 16px; display: inline-flex;
                  align-items: center; justify-content: center; vertical-align: -3px; }
i.fi { line-height: 0; font-style: normal; }
i.fi::before { font-size: 15px; line-height: 1; }
i.fi.ic-lg { width: 22px; height: 22px; flex-basis: 22px; }
i.fi.ic-lg::before { font-size: 21px; }
i.fi.ic-xl { width: 30px; height: 30px; flex-basis: 30px; }
i.fi.ic-xl::before { font-size: 28px; }
.btn svg.ic { width: 15px; height: 15px; flex-basis: 15px; }
.side-link svg.ic { width: 18px; height: 18px; flex-basis: 18px; }
.flash svg.ic { width: 18px; height: 18px; flex-basis: 18px; margin-top: 2px; }
.nav-toggle svg.ic { width: 17px; height: 17px; flex-basis: 17px; }
.search svg.ic { width: 14px; height: 14px; flex-basis: 14px; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }
::selection { background: var(--accent-soft); }

/* ---------- โครงหน้า ---------- */
.app { display: grid; grid-template-columns: 236px minmax(0,1fr); min-height: 100vh; }
.app.nav-collapsed { grid-template-columns: 64px minmax(0,1fr); }

/* ---------- แถบนำทางซ้าย ---------- */
.side {
  background: var(--nav-bg); color: var(--nav-text);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
  border-right: 1px solid var(--nav-border);
}
.side-brand {
  display: flex; align-items: center; gap: 10px;
  padding: 16px 18px; border-bottom: 1px solid var(--nav-border); min-height: 60px;
}
.side-mark {
  width: 28px; height: 28px; border-radius: 7px; flex: 0 0 28px;
  background: linear-gradient(145deg, var(--accent), #0a4f4a);
  display: grid; place-items: center; color: #fff;
  font-family: var(--font-display); font-weight: 700; font-size: .82rem;
}
.side-name { font-family: var(--font-display); font-weight: 700; font-size: 1.02rem; color: #fff; letter-spacing: -.01em; }
.side-ver { font-family: var(--font-mono); font-size: .6rem; color: var(--nav-text-dim); letter-spacing: .06em; }

.side-nav { flex: 1; padding: 12px 10px; display: flex; flex-direction: column; gap: 2px; }
.side-group {
  font-family: var(--font-mono); font-size: .58rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--nav-text-dim); padding: 14px 10px 5px;
}
.side-link {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: var(--r-sm);
  color: var(--nav-text); font-size: .88rem; text-decoration: none;
  transition: background .12s, color .12s;
}
.side-link:hover { background: var(--nav-active); color: #fff; text-decoration: none; }
.side-link.on { background: var(--accent); color: var(--accent-ink); font-weight: 500; }
.side-link .ic { flex: 0 0 18px; width: 18px; height: 18px; opacity: .85; }
.side-link.on .ic { opacity: 1; }
.side-link .badge {
  margin-left: auto; font-family: var(--font-mono); font-size: .62rem;
  background: rgba(255,255,255,.14); padding: 1px 6px; border-radius: 20px;
}
.side-link.on .badge { background: rgba(255,255,255,.25); }
.side-foot { padding: 12px; border-top: 1px solid var(--nav-border); }

.app.nav-collapsed .side-name, .app.nav-collapsed .side-ver,
.app.nav-collapsed .side-group, .app.nav-collapsed .side-link span:not(.badge),
.app.nav-collapsed .side-foot .who-name { display: none; }
.app.nav-collapsed .side-link { justify-content: center; padding: 9px 0; }
.app.nav-collapsed .side-brand { justify-content: center; padding: 16px 0; }

/* ---------- แถบบน ---------- */
.main { min-width: 0; display: flex; flex-direction: column; }
.top {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 14px;
  padding: 11px 26px; min-height: 60px;
}
.top h1 { font-family: var(--font-display); font-weight: 600; font-size: 1.12rem; margin: 0; letter-spacing: -.01em; }
.top .sub { font-size: .78rem; color: var(--text-3); margin-top: 1px; }
.top-actions { margin-left: auto; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.nav-toggle {
  background: none; border: 1px solid var(--border); color: var(--text-2);
  width: 32px; height: 32px; border-radius: var(--r-sm); cursor: pointer;
  display: grid; place-items: center; flex: 0 0 32px;
}
.nav-toggle:hover { border-color: var(--accent); color: var(--accent); }

.sysdot { display: inline-flex; align-items: center; gap: 6px; font-size: .76rem; color: var(--text-3); }
.sysdot i { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); flex: 0 0 7px; }
.sysdot.busy i { background: var(--warn); }
.sysdot.bad  i { background: var(--crit); }

.wrap { padding: 22px 26px 72px; max-width: 1440px; width: 100%; }

/* ---------- การ์ด ---------- */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r); box-shadow: var(--shadow-sm); margin-bottom: var(--gap);
}
.card-head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 13px 18px; border-bottom: 1px solid var(--border);
}
.card-head h2 { font-family: var(--font-display); font-weight: 600; font-size: .98rem; margin: 0; }
.card-head .sub { font-size: .78rem; color: var(--text-3); }
.card-head .right { margin-left: auto; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
/* .card-body คือ "เนื้อที่มีระยะขอบ" เสมอ แม้ในการ์ด flush
   ตารางที่ต้องการชนขอบให้วาง .tbl-wrap เป็นลูกตรงของการ์ดแทน อย่าใส่ไว้ในนี้
   (เดิม flush ตัด padding ทิ้ง ทำให้ข้อความในการ์ดเดียวกันไปชนเส้นกรอบ) */
.card-body { padding: 18px; }
.card-body > :first-child { margin-top: 0; }
.card-body > :last-child { margin-bottom: 0; }
.card.flush > .card-body { padding: 16px 18px; }
.card.flush > .card-head + .card-body { padding-top: 15px; }

h2.sec { font-family: var(--font-display); font-weight: 600; font-size: 1rem; margin: 26px 0 12px; }
p { margin: 0 0 .9em; }
p.hint { font-size: .82rem; color: var(--text-3); }

/* ---------- ตัวเลขสรุป ---------- */
.stats { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(184px,1fr)); margin-bottom: var(--gap); }
.stat {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r); padding: 14px 16px; position: relative; overflow: hidden;
}
.stat::before { content:""; position:absolute; inset:0 auto 0 0; width:3px; background: var(--border-strong); }
.stat.ok::before   { background: var(--ok); }
.stat.warn::before { background: var(--warn); }
.stat.crit::before { background: var(--crit); }
.stat.accent::before { background: var(--accent); }
.stat small {
  display: block; font-family: var(--font-mono); font-size: .6rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-3); margin-bottom: 4px;
}
.stat b { font-family: var(--font-display); font-size: 1.72rem; font-weight: 600; line-height: 1.15; display: block; }
.stat .meta { font-size: .78rem; color: var(--text-3); margin-top: 3px; }
.stat a { color: inherit; }

/* ---------- ตาราง ---------- */
.tbl-wrap { overflow-x: auto; border-radius: var(--r); }
.card.flush .tbl-wrap { border-radius: 0 0 var(--r) var(--r); }
.card.flush > .card-body + .tbl-wrap { border-top: 1px solid var(--border); }
table.tbl { width: 100%; border-collapse: collapse; font-size: .86rem; }
table.tbl th {
  position: sticky; top: 0; z-index: 1;
  text-align: left; font-family: var(--font-mono); font-weight: 500;
  font-size: .6rem; letter-spacing: .1em; text-transform: uppercase; color: var(--text-3);
  padding: 9px 14px; background: var(--surface-2); border-bottom: 1px solid var(--border); white-space: nowrap;
}
table.tbl td { padding: var(--row-y) 14px; border-bottom: 1px solid var(--border); color: var(--text-2); vertical-align: middle; }
table.tbl tbody tr:last-child td { border-bottom: 0; }
table.tbl tbody tr:hover td { background: var(--surface-2); }
table.tbl td b, table.tbl td strong { color: var(--text); font-weight: 600; }
.num { text-align: right; white-space: nowrap; }
.mono { font-family: var(--font-mono); font-size: .8rem; }
.muted { color: var(--text-3); }
.nowrap { white-space: nowrap; }
.sub2 { font-size: .74rem; color: var(--text-3); margin-top: 1px; }

/* ---------- ป้ายสถานะ ---------- */
.pill {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: .7rem; font-weight: 500; padding: 2px 9px; border-radius: 20px;
  white-space: nowrap; border: 1px solid transparent;
}
.pill::before { content:""; width:6px; height:6px; border-radius:50%; background: currentColor; flex:0 0 6px; }
.pill.plain::before { display: none; }
.pill.normal, .pill.active, .pill.published, .pill.succeeded, .pill.done, .pill.high-conf
  { background: var(--ok-soft);   color: var(--ok);   border-color: color-mix(in srgb, var(--ok) 26%, transparent); }
.pill.watch, .pill.degraded, .pill.draft, .pill.pending, .pill.queued, .pill.medium-conf
  { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 26%, transparent); }
.pill.high, .pill.validated, .pill.running
  { background: var(--high-soft); color: var(--high); border-color: color-mix(in srgb, var(--high) 26%, transparent); }
.pill.danger, .pill.offline, .pill.failed, .pill.dead, .pill.retracted, .pill.disabled, .pill.low-conf
  { background: var(--crit-soft); color: var(--crit); border-color: color-mix(in srgb, var(--crit) 26%, transparent); }
.pill.approved, .pill.info
  { background: var(--info-soft); color: var(--info); border-color: color-mix(in srgb, var(--info) 26%, transparent); }
.pill.ghost { background: var(--surface-sunk); color: var(--text-3); border-color: var(--border); }
.pill.solid { color: #fff; }
.pill.solid::before { background: rgba(255,255,255,.85); }

.role {
  font-family: var(--font-mono); font-size: .62rem; letter-spacing: .06em; text-transform: uppercase;
  padding: 2px 7px; border-radius: var(--r-sm); background: var(--accent-soft); color: var(--accent);
}
.role.admin     { background: var(--crit-soft); color: var(--crit); }
.role.publisher { background: var(--info-soft); color: var(--info); }
.role.reviewer  { background: var(--high-soft); color: var(--high); }
.role.steward   { background: var(--warn-soft); color: var(--warn); }
.role.viewer    { background: var(--surface-sunk); color: var(--text-3); }

/* ---------- ปุ่ม ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  font-family: inherit; font-size: .84rem; font-weight: 500;
  padding: var(--pad-y-sm) 13px; border-radius: var(--r-sm);
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--text);
  cursor: pointer; white-space: nowrap; text-decoration: none;
  transition: border-color .12s, background .12s, color .12s;
}
.btn:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--accent-ink); }
.btn.danger { border-color: color-mix(in srgb, var(--crit) 45%, transparent); color: var(--crit); }
.btn.danger:hover { background: var(--crit); border-color: var(--crit); color: #fff; }
.btn.ghost { border-color: transparent; background: transparent; color: var(--text-2); }
.btn.ghost:hover { background: var(--surface-sunk); color: var(--text); }
.btn.sm { font-size: .76rem; padding: 3px 9px; }
.btn[disabled], .btn.is-disabled { opacity: .45; pointer-events: none; }
.btn-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

/* ---------- ฟอร์ม ---------- */
.form-grid { display: grid; gap: 14px 18px; grid-template-columns: repeat(auto-fit, minmax(210px,1fr)); }
.form-grid.two { grid-template-columns: repeat(auto-fit, minmax(280px,1fr)); }
.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field.span2 { grid-column: span 2; }
@media (max-width: 640px) { .field.span2 { grid-column: auto; } }
label { font-size: .8rem; font-weight: 500; color: var(--text-2); }
label .req { color: var(--crit); }
/* เลือกแบบ "ทุกช่องกรอก ยกเว้นที่ไม่ใช่" — ถ้าไล่ชนิดทีละอัน วันที่ลืมใส่ type="text"
   ช่องนั้นจะกลายเป็นกล่องขาวของเบราว์เซอร์เงียบ ๆ (เกิดมาแล้วกับฟอร์มสถานี)
   ห่อด้วย :where() เพื่อให้ค่าความจำเพาะเป็นศูนย์ กฎเฉพาะทางอย่าง .search input จะได้ยังชนะ */
input:where(:not([type=checkbox], [type=radio], [type=range], [type=file],
                 [type=submit], [type=button], [type=reset], [type=image], [type=color], [type=hidden])),
select, textarea {
  width: 100%; padding: var(--pad-y) 11px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text);
  font-family: inherit; font-size: .88rem; transition: border-color .12s, box-shadow .12s;
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring);
}
input::placeholder { color: var(--text-3); }
select {
  appearance: none; padding-right: 32px; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 17px) 52%, calc(100% - 12px) 52%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
textarea { resize: vertical; min-height: 74px; }
.help { font-size: .74rem; color: var(--text-3); line-height: 1.5; }
.check { display: flex; align-items: flex-start; gap: 9px; cursor: pointer; }
.check input { width: 16px; height: 16px; margin-top: 3px; flex: 0 0 16px; accent-color: var(--accent); cursor: pointer; }
.check .t { font-size: .84rem; color: var(--text-2); }

fieldset { border: 0; padding: 0; margin: 0 0 22px; }
fieldset > legend {
  font-family: var(--font-mono); font-size: .62rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent); padding: 0 0 9px; margin-bottom: 14px;
  border-bottom: 1px solid var(--border); width: 100%;
}

.form-actions {
  position: sticky; bottom: 0; margin: 0 -18px -18px; padding: 13px 18px;
  background: var(--surface-2); border-top: 1px solid var(--border);
  border-radius: 0 0 var(--r) var(--r);
  display: flex; gap: 9px; align-items: center; flex-wrap: wrap;
}

/* ---------- ตัวเลือกแบบแถบ (ธีม/ขนาด) ---------- */
.seg { display: inline-flex; background: var(--surface-sunk); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 2px; gap: 2px; }
.seg label { display: block; margin: 0; }
.seg input { position: absolute; opacity: 0; pointer-events: none; }
.seg .opt {
  display: block; padding: 5px 12px; border-radius: 4px; font-size: .8rem; color: var(--text-2);
  cursor: pointer; user-select: none; white-space: nowrap; transition: background .12s, color .12s;
}
.seg .opt:hover { color: var(--text); }
/* ตัวเลือกที่เลือกอยู่ต้องเห็นชัดทั้งสองธีม
   ใช้พื้นสีเน้น + เส้นขอบ แทนการพึ่งความต่างของเฉดพื้นผิวอย่างเดียว
   (ในโหมดมืด surface กับ surface-sunk ต่างกันน้อยมากจนมองไม่ออกว่าเลือกอะไร) */
.seg input:checked + .opt {
  background: var(--accent-soft); color: var(--accent); font-weight: 600;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent);
}
.seg input:focus-visible + .opt { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ---------- แจ้งเตือน ---------- */
.flash {
  display: flex; gap: 11px; align-items: flex-start;
  padding: 12px 16px; border-radius: var(--r); margin-bottom: var(--gap);
  border: 1px solid; font-size: .87rem; line-height: 1.55;
}
.flash.ok   { background: var(--ok-soft);   border-color: color-mix(in srgb, var(--ok) 28%, transparent);   color: var(--text); }
.flash.err  { background: var(--crit-soft); border-color: color-mix(in srgb, var(--crit) 28%, transparent); color: var(--text); }
.flash.warn { background: var(--warn-soft); border-color: color-mix(in srgb, var(--warn) 28%, transparent); color: var(--text); }
.flash .ic { flex: 0 0 18px; margin-top: 1px; }

.note {
  background: var(--surface-sunk); border-left: 3px solid var(--accent);
  padding: 11px 15px; border-radius: 0 var(--r-sm) var(--r-sm) 0;
  font-size: .82rem; color: var(--text-2); line-height: 1.6;
}
.note.warn { border-left-color: var(--warn); }
.note.crit { border-left-color: var(--crit); }

.empty { padding: 46px 24px; text-align: center; color: var(--text-3); }
.empty .big { font-family: var(--font-display); font-size: 1rem; color: var(--text-2); margin-bottom: 5px; }
.empty .btn { margin-top: 14px; }

/* ---------- รายละเอียดคู่คีย์-ค่า ---------- */
dl.kv { display: grid; grid-template-columns: 168px minmax(0,1fr); gap: 0; margin: 0; }
dl.kv dt {
  font-family: var(--font-mono); font-size: .62rem; letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-3); padding: 10px 12px 10px 0; border-top: 1px solid var(--border);
}
dl.kv dd { margin: 0; padding: 10px 0; border-top: 1px solid var(--border); font-size: .86rem; min-width: 0; }
dl.kv dt:first-of-type, dl.kv dd:first-of-type { border-top: 0; }
@media (max-width: 620px) {
  dl.kv { grid-template-columns: 1fr; }
  dl.kv dd { border-top: 0; padding-top: 0; }
}

/* ---------- กราฟ ---------- */
.spark { display: block; width: 100%; height: auto; color: var(--accent); }
.legend { display: flex; gap: 15px; flex-wrap: wrap; font-size: .76rem; color: var(--text-3); margin-top: 9px; }
.legend i { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: 5px; }

pre.code {
  font-family: var(--font-mono); font-size: .76rem; line-height: 1.65;
  background: var(--surface-sunk); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: 13px 15px; overflow-x: auto; max-height: 420px; margin: 0;
}
code { font-family: var(--font-mono); font-size: .86em; background: var(--accent-soft); color: var(--accent); padding: .08em .38em; border-radius: 3px; }
pre.code code { background: none; color: inherit; padding: 0; }
details > summary { cursor: pointer; font-size: .84rem; color: var(--accent); padding: 4px 0; }
details[open] > summary { margin-bottom: 9px; }

/* จัดชิดล่าง ไม่ใช่กึ่งกลาง — ช่องกรอกในแถบเครื่องมือมี label อยู่ข้างบน
   ปุ่มที่ไม่มี label จึงต้องเสมอกับ "ช่องกรอก" ไม่ใช่เสมอกับกล่องทั้งใบที่รวม label ด้วย
   (align-items:center ทำให้ปุ่มลอยสูงกว่าช่องกรอกครึ่งความสูงของ label) */
.toolbar { display: flex; gap: 9px; align-items: flex-end; flex-wrap: wrap; margin-bottom: 14px; }
/* ของที่ไม่ใช่ช่องกรอก (ข้อความสถานะ ฯลฯ) ให้อยู่แนวเดียวกับปุ่ม */
.toolbar > .muted, .toolbar > span:not(.search) { padding-bottom: 9px; }
.toolbar .grow { flex: 1; min-width: 160px; }
.search { position: relative; display: block; }
.search input { padding-left: 32px; width: 100%; }
.search .ic { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--text-3); pointer-events: none; }
/* เผื่อมีคนใส่ .search ไว้บนกล่องที่มี label ด้วย — ยึดไอคอนกับช่องกรอก ไม่ใช่กลางกล่อง */
.field.search { position: relative; }
.field.search > .ic { top: auto; bottom: 11px; transform: none; }

.bar { height: 5px; border-radius: 3px; background: var(--surface-sunk); overflow: hidden; min-width: 54px; }
.bar > span { display: block; height: 100%; border-radius: 3px; background: var(--accent); }

/* ---------- หน้าเข้าสู่ระบบ ---------- */
/* ---------- หน้าเข้าสู่ระบบ ---------- */
/* สองแผง: ซ้ายเป็นแบรนด์บนพื้นเข้มชุดเดียวกับแถบเมนู (โลโก้จึงอยู่ในบริบทเดิม
   ที่มันถูกออกแบบมาให้อ่านออก) ขวาเป็นฟอร์มบนพื้นสว่างตามปกติของระบบ
   จอแคบกว่า 900px แผงซ้ายยุบเป็นแถบหัวสั้น ๆ แล้วซ่อนส่วนที่ไม่จำเป็น */
.auth {
  min-height: 100dvh; background: var(--bg);
  display: grid; grid-template-columns: minmax(0, 42%) minmax(0, 1fr);
}

.auth-side {
  position: relative; overflow: hidden;
  background: var(--nav-bg); color: var(--nav-text);
  display: flex; align-items: center;
  padding: 48px clamp(28px, 4vw, 56px);
  max-width: 560px;
  /* โหมดมืด พื้นแผงกับพื้นหน้าเกือบเท่ากัน ถ้าไม่มีเส้นคั่นจะกลืนกันจนไม่รู้ว่าแยกแผง */
  border-right: 1px solid var(--nav-border);
}
/* เส้นชั้นความสูงเป็นพื้นหลัง — จางพอที่จะไม่แย่งความสนใจจากฟอร์ม
   แต่ยังบอกได้ว่านี่คือระบบที่ทำงานกับภูมิประเทศ */
/* ครอบให้เลยขอบแผงออกไป — เห็นเป็นชิ้นส่วนของแผนที่ ไม่ใช่ลายที่จัดวางไว้กลางกรอบ */
.auth-relief {
  position: absolute; inset: 0; width: 100%; height: 100%;
  color: var(--nav-accent); opacity: .55; pointer-events: none;
}
.auth-side-in { position: relative; width: 100%; max-width: 380px; }

.auth-brand { display: flex; align-items: center; gap: 11px; margin-bottom: 20px; }
.auth-brand .side-mark { width: 38px; height: 38px; flex-basis: 38px; font-size: 1rem; border-radius: 9px; }
.auth-brand h1 {
  font-family: var(--font-display); font-size: 1.6rem; margin: 0;
  letter-spacing: -.02em; color: #fff;
}
.auth-lead {
  font-size: .94rem; line-height: 1.7; color: var(--nav-text);
  margin: 0 0 30px; max-width: 34ch;
}

/* กฎที่บังคับใช้จริงในระบบ ไม่ใช่คำโฆษณา — จึงจัดเป็นรายการมีหัวข้อกำกับ
   ไม่ใช่ประโยคลอย ๆ ต่อกัน */
.auth-facts { list-style: none; margin: 0; padding: 0; display: grid; gap: 17px; }
.auth-facts li { display: grid; gap: 3px; padding-left: 15px; position: relative; }
.auth-facts li::before {
  content: ""; position: absolute; left: 0; top: 5px; bottom: 3px;
  width: 2px; border-radius: 1px; background: var(--nav-accent); opacity: .7;
}
.auth-facts .k {
  font-family: var(--font-mono); font-size: .6rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--nav-accent);
}
.auth-facts .v { font-size: .82rem; line-height: 1.65; color: var(--nav-text-dim); }

.auth-side-foot {
  display: flex; align-items: center; gap: 9px; margin-top: 34px;
  padding-top: 16px; border-top: 1px solid var(--nav-border);
  font-size: .7rem; color: var(--nav-text-dim); letter-spacing: .04em;
}
.auth-side-foot .mono { font-family: var(--font-mono); }

.auth-main { display: grid; place-items: center; padding: 40px 24px; }
.auth-box { width: 100%; max-width: 372px; }
.auth-top { display: flex; align-items: baseline; gap: 12px; margin-bottom: 22px; }
.auth-top h2 {
  font-family: var(--font-display); font-weight: 600; font-size: 1.32rem;
  margin: 0; letter-spacing: -.01em;
}
.auth-lang { margin-left: auto; display: flex; gap: 2px; }
.auth-lang a {
  font-size: .74rem; padding: 4px 9px; border-radius: var(--r-sm);
  color: var(--text-3); text-decoration: none;
}
.auth-lang a:hover { background: var(--surface-2); color: var(--text); }
.auth-lang a.on { background: var(--surface-2); color: var(--text); font-weight: 600; }

.auth-box form { display: block; }
.auth-note {
  display: flex; gap: 9px; align-items: flex-start; margin: 22px 0 0;
  font-size: .77rem; line-height: 1.65; color: var(--text-3);
}
.auth-note .ic { flex: 0 0 auto; margin-top: 2px; opacity: .75; }

@media (max-width: 900px) {
  .auth { grid-template-columns: 1fr; align-content: start; }
  .auth-side { max-width: none; padding: 26px 24px 24px; align-items: flex-start;
               border-right: 0; border-bottom: 1px solid var(--nav-border); }
  .auth-side-in { max-width: none; }
  /* บนจอแคบพื้นที่จำกัด — เก็บแค่แบรนด์กับประโยคเดียวที่บอกว่านี่คือระบบอะไร */
  .auth-facts, .auth-side-foot { display: none; }
  .auth-lead { margin-bottom: 0; font-size: .86rem; }
  .auth-relief { opacity: .35; }
  .auth-main { padding: 30px 24px 48px; align-items: start; }
}

@media (max-width: 860px) {
  .app { grid-template-columns: 1fr; }
  .side {
    position: fixed; inset: 0 auto 0 0; width: 236px; z-index: 60;
    transform: translateX(-100%); transition: transform .18s ease;
  }
  .app.nav-open .side { transform: none; box-shadow: var(--shadow-lg); }
  .app.nav-open::after { content:""; position: fixed; inset: 0; background: rgba(0,0,0,.4); z-index: 50; }
  .wrap, .top { padding-left: 16px; padding-right: 16px; }
}
@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }

/* =====================================================================
   ชั้นเชื่อมกับมาร์กอัปเดิม — ให้ทุกหน้าเข้ากับระบบภาพใหม่ทันที
   โดยไม่ต้องแก้ HTML ทุกไฟล์พร้อมกัน
   ===================================================================== */
.page-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 14px; flex-wrap: wrap; margin-bottom: 14px;
}
.page-head h1 { font-family: var(--font-display); font-weight: 600; font-size: 1.22rem; margin: 0 0 2px; letter-spacing: -.01em; }
.page-head h2 { font-family: var(--font-display); font-weight: 600; font-size: 1rem; margin: 0; }
.page-head .sub { font-size: .8rem; color: var(--text-3); margin: 0; }

.grid { display: grid; gap: 14px; }
.g2 { grid-template-columns: repeat(auto-fit, minmax(300px,1fr)); }
.g3 { grid-template-columns: repeat(auto-fit, minmax(224px,1fr)); }
.g4 { grid-template-columns: repeat(auto-fit, minmax(184px,1fr)); }

/* ตารางที่ยังไม่ได้ใส่ class="tbl" ให้ได้หน้าตาเดียวกัน */
.tbl-wrap { border: 1px solid var(--border); background: var(--surface); }
.tbl-wrap table { width: 100%; border-collapse: collapse; font-size: .86rem; }
.tbl-wrap th {
  position: sticky; top: 0; z-index: 1; text-align: left;
  font-family: var(--font-mono); font-weight: 500; font-size: .6rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-3);
  padding: 9px 14px; background: var(--surface-2); border-bottom: 1px solid var(--border); white-space: nowrap;
}
.tbl-wrap td { padding: var(--row-y) 14px; border-bottom: 1px solid var(--border); color: var(--text-2); vertical-align: middle; }
.tbl-wrap tbody tr:last-child td { border-bottom: 0; }
.tbl-wrap tbody tr:hover td { background: var(--surface-2); }
.tbl-wrap td b, .tbl-wrap td strong { color: var(--text); font-weight: 600; }

.stat .hint { font-size: .78rem; color: var(--text-3); margin-top: 3px; }
pre.json {
  font-family: var(--font-mono); font-size: .76rem; line-height: 1.65;
  background: var(--surface-sunk); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: 13px 15px; overflow-x: auto; max-height: 420px; margin: 0;
}
.legend-row { display: flex; gap: 15px; flex-wrap: wrap; font-size: .76rem; color: var(--text-3); margin-top: 9px; }
.legend-row i { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: 5px; }

.card > h2:first-child { margin-top: 0; }
.card h2 { font-family: var(--font-display); font-weight: 600; font-size: 1rem; margin: 0 0 12px; }
.card { padding: 18px; }          /* หน้าเดิมวางเนื้อหาในการ์ดโดยตรง */
.card.flush { padding: 0; }

/* เดิมบรรทัดนี้เป็น .card:has(> .card-head) { padding: 0 } ซึ่งตัด padding ทั้งใบ
   การ์ดที่มีหัวแล้วตามด้วยเนื้อหาปกติ (เช่นฟอร์มรันโมเดล) จึงชนขอบกรอบสนิท
   วิธีที่ถูกคือคง padding ไว้ แล้วดึงเฉพาะส่วนที่ต้องชิดขอบออกมาด้วย margin ลบ */
/* margin ลบมีไว้ดึงหัวการ์ดออกจาก padding 18px ของการ์ดปกติ
   .card.flush ไม่มี padding อยู่แล้ว ถ้าโดนด้วยหัวจะล้นออกนอกกรอบข้างละ 18px */
.card:not(.flush) > .card-head:first-child { margin: -18px -18px 16px; }
.card:not(.flush) > .card-head:only-child  { margin: -18px; border-bottom: 0; }
.card:not(.flush) > .card-body { margin: -18px; }
/* ตารางที่อยู่ในการ์ด ไม่ต้องมีกรอบของตัวเอง — การ์ดเป็นกรอบให้อยู่แล้ว
   ไม่งั้นจะเห็นเส้นสองชั้นซ้อนกัน (กรอบการ์ด + กรอบตาราง)
   ใช้ตัวเลือกแบบลูกหลาน ให้ CSS ตัดสินการซ้อนเอง ไม่ต้องเดาจากโครงไฟล์ */
.card .tbl-wrap { border: 0; background: transparent; border-radius: 0; }

/* ตารางที่เป็นลูกโดยตรงให้กินเต็มความกว้างการ์ด และมีเส้นคั่นจากหัวข้อด้านบน */
.card:not(.flush) > .tbl-wrap {
  margin: 14px -18px -18px; border-top: 1px solid var(--border);
}
/* margin ล่างติดลบมีไว้ให้ตารางชนขอบล่างของการ์ด — ถูกเฉพาะตอนตารางเป็นลูกตัวสุดท้าย
   ถ้ามีเนื้อหาตามหลัง (เช่นบรรทัดวิธีคำนวณใต้ตาราง) มันจะดึงเนื้อหานั้นขึ้นมาทับตาราง */
.card:not(.flush) > .tbl-wrap:not(:last-child) {
  margin-bottom: 16px; border-bottom: 1px solid var(--border);
}
.card:not(.flush) > .tbl-wrap:first-child { margin-top: -18px; border-top: 0; }
.card:not(.flush) > .card-head + .tbl-wrap { margin-top: 0; border-top: 0; }
.card > :first-child { margin-top: 0; }
.card > :last-child  { margin-bottom: 0; }

.field .help { font-size: .74rem; color: var(--text-3); margin-top: 3px; line-height: 1.5; }
.field label { display: block; margin-bottom: 4px; }
.field { display: block; margin-bottom: 0; }

.flag2 { color: var(--warn); font-weight: 600; }
.flag3 { color: var(--crit); font-weight: 600; }

/* ---------- ตัวเลือกชุดสี ---------- */
.swatches { display: flex; flex-wrap: wrap; gap: 10px; }
.swatch { position: relative; cursor: pointer; text-align: center; width: 74px; }
.swatch input { position: absolute; opacity: 0; pointer-events: none; }
/* วงกลมตัวอย่างสร้างจาก --h/--cs ชุดเดียวกับที่ธีมใช้จริง ตัวอย่างจึงตรงกับของจริงเสมอ */
.swatch .sw {
  display: block; width: 100%; height: 34px; border-radius: var(--r-sm);
  background: linear-gradient(135deg,
    oklch(47.7% calc(.080 * var(--cs)) var(--h)) 0 52%,
    oklch(73.2% calc(.111 * var(--cs)) var(--h)) 52% 100%);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.14);
  transition: transform .12s, box-shadow .12s;
}
.swatch .nm { display: block; font-size: .72rem; color: var(--text-3); margin-top: 4px; }
.swatch:hover .sw { transform: translateY(-1px); }
.swatch input:checked + .sw {
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.14), 0 0 0 2px var(--surface), 0 0 0 4px var(--accent);
}
.swatch input:checked ~ .nm { color: var(--text); font-weight: 600; }
.swatch input:focus-visible + .sw { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ---------- ตัวอย่างแบบอักษร ---------- */
.font-samples {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 7px; margin-top: 12px;
}
.fsample { position: relative; cursor: pointer; }
.fsample input { position: absolute; opacity: 0; pointer-events: none; }
.fsample > span {
  display: block; padding: 9px 12px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--surface-2);
  transition: border-color .12s, background .12s;
}
.fsample b  { display: block; font-size: .88rem; font-weight: 600; color: var(--text); }
.fsample em { display: block; font-style: normal; font-size: .78rem; color: var(--text-3); margin-top: 2px;
              white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fsample:hover > span { border-color: var(--border-strong); }
.fsample input:checked + span {
  background: var(--accent-soft); border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.fsample input:checked + span b { color: var(--accent); }
.fsample input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- กล่องยืนยัน (modal) ---------- */
/* แทน confirm() ของเบราว์เซอร์ ซึ่งใช้ชุดสีของระบบปฏิบัติการ อ่านคำถามยาว ๆ ยาก
   และตัดข้อความเมื่อยาว — งานที่ลบข้อมูลหรือกินเวลาเป็นนาที ผู้ใช้ต้องอ่านให้ครบก่อนกด */
.modal-back {
  position: fixed; inset: 0; z-index: 200;
  background: color-mix(in srgb, oklch(12% .01 var(--h)) 62%, transparent);
  backdrop-filter: blur(3px);
  display: grid; place-items: center; padding: 20px;
  opacity: 0; pointer-events: none; transition: opacity .16s ease;
}
.modal-back.on { opacity: 1; pointer-events: auto; }
.modal {
  width: min(460px, 100%); background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg); overflow: hidden;
  transform: translateY(8px) scale(.985); transition: transform .16s ease;
}
.modal-back.on .modal { transform: none; }
.modal-head { display: flex; gap: 13px; align-items: flex-start; padding: 20px 22px 0; }
.modal-head .mi {
  width: 40px; height: 40px; flex: 0 0 40px; border-radius: 50%;
  display: grid; place-items: center; background: var(--accent-soft); color: var(--accent);
}
.modal-head .mi i.fi::before { font-size: 20px; }
.modal.danger .modal-head .mi { background: var(--crit-soft); color: var(--crit); }
.modal.warn   .modal-head .mi { background: var(--warn-soft); color: var(--warn); }
.modal h3 { margin: 6px 0 0; font-size: 1.02rem; font-weight: 600; color: var(--text); }
.modal-body { padding: 10px 22px 4px 75px; color: var(--text-2); font-size: .88rem; line-height: 1.65; }
.modal-body .note { margin-top: 10px; }
.modal-foot {
  display: flex; justify-content: flex-end; gap: 9px;
  padding: 16px 22px 18px; margin-top: 8px;
}
@media (max-width: 520px) {
  .modal-body { padding-left: 22px; }
  .modal-foot { flex-direction: column-reverse; }
  .modal-foot .btn { width: 100%; justify-content: center; }
}

/* ---------- การ์ดกดเข้าไป (ประเภทภัย / โมเดล) ---------- */
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 12px; }
/* การ์ดทั้งใบเป็นลิงก์ — ต้องปิดเส้นใต้ทั้งตอนปกติและตอนชี้
   ถ้าตั้งแค่สถานะปกติ กฎ a:hover ด้านบนจะชนะแล้วขีดเส้นใต้ข้อความทุกบรรทัดในการ์ด */
.tile, .tile:hover, .tile:focus { text-decoration: none; }
.tile {
  display: flex; align-items: center; gap: 15px;
  padding: 16px 18px; color: inherit;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
  transition: border-color .13s, transform .13s, box-shadow .13s, background .13s;
}
.tile:hover {
  border-color: var(--accent); transform: translateY(-1px);
  box-shadow: var(--shadow); background: var(--surface-2);
}
.tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tile-ic {
  width: 52px; height: 52px; flex: 0 0 52px; border-radius: var(--r);
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent);
  transition: background .13s;
}
.tile-ic.sm { width: 40px; height: 40px; flex-basis: 40px; }
.tile:hover .tile-ic { background: color-mix(in srgb, var(--accent) 18%, var(--surface)); }
.tile-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.tile-body b { font-size: .96rem; font-weight: 600; color: var(--text); }
.tile-meta { font-size: .78rem; color: var(--text-2); }
.tile-sub  { font-size: .76rem; color: var(--text-3); }
.tile-body .tile-meta, .tile-body .tile-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tile-go { display: flex; align-items: center; gap: 8px; color: var(--text-3); flex: 0 0 auto; }
.tile:hover .tile-go { color: var(--accent); }

/* หัวการ์ดที่มีไอคอนนำ */
.card-head .ttl { display: flex; align-items: center; gap: 13px; }

/* ---------- แถบความคืบหน้า ---------- */
.modal.prog .modal-body { padding-left: 75px; }
.pbar {
  height: 9px; border-radius: 99px; overflow: hidden;
  background: var(--surface-sunk); box-shadow: inset 0 0 0 1px var(--border);
}
.pbar > span {
  display: block; height: 100%; width: 2%; border-radius: 99px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--accent) 70%, transparent), var(--accent));
  transition: width .35s cubic-bezier(.4, 0, .2, 1);
  position: relative; overflow: hidden;
}
/* ลายวิ่งบาง ๆ บอกว่ายังทำงานอยู่ แม้ตัวเลขจะค้างที่ขั้นเดิมนาน */
.pbar > span::after {
  content: ''; position: absolute; inset: 0;
  background: repeating-linear-gradient(115deg,
    rgba(255,255,255,.18) 0 10px, transparent 10px 22px);
  animation: pbar-move 1s linear infinite;
}
@keyframes pbar-move { to { transform: translateX(22px); } }
@media (prefers-reduced-motion: reduce) { .pbar > span::after { animation: none; } }
.modal.danger .pbar > span { background: var(--crit); }
.modal.danger .pbar > span::after { animation: none; }

.prow { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin-top: 9px; }
.prow .pmsg { font-size: .84rem; color: var(--text-2); }
.prow .ppct { font-family: var(--font-mono); font-size: .9rem; color: var(--accent); font-variant-numeric: tabular-nums; }

/* ---------- เมนูผู้ใช้ (มุมขวาบน) ---------- */
.umenu { position: relative; }
.umenu-btn {
  display: flex; align-items: center; gap: 9px;
  padding: 5px 9px 5px 5px; border-radius: 99px;
  border: 1px solid var(--border); background: var(--surface);
  color: var(--text); cursor: pointer; font-family: inherit;
  transition: border-color .13s, background .13s;
}
.umenu-btn:hover { border-color: var(--accent); background: var(--surface-2); }
.umenu-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.umenu.open .umenu-btn { border-color: var(--accent); background: var(--surface-2); }

.uava {
  width: 30px; height: 30px; flex: 0 0 30px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent); color: var(--accent-ink);
  font-weight: 600; font-size: .92rem; line-height: 1;
}
.uava.lg { width: 46px; height: 46px; flex-basis: 46px; font-size: 1.3rem; }

.uname { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.25; }
.uname b     { font-size: .84rem; font-weight: 600; }
.uname small { font-size: .72rem; color: var(--text-3); }
.ucaret { transition: transform .15s; color: var(--text-3); }
.umenu.open .ucaret { transform: rotate(90deg); color: var(--accent); }
@media (max-width: 720px) { .uname { display: none; } }

.umenu-panel {
  position: absolute; top: calc(100% + 9px); right: 0; z-index: 90;
  width: min(520px, calc(100vw - 32px));
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg); overflow: hidden;
  opacity: 0; transform: translateY(-6px); pointer-events: none;
  transition: opacity .14s ease, transform .14s ease;
}
.umenu.open .umenu-panel { opacity: 1; transform: none; pointer-events: auto; }
.umenu-panel[hidden] { display: none; }

.umenu-head {
  display: flex; gap: 13px; align-items: center;
  padding: 16px 18px; background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.umenu-head > div { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.umenu-head b { font-size: .98rem; }
.umenu-head .mono { font-size: .76rem; color: var(--text-3); }
.umenu-head .pill { align-self: flex-start; margin-top: 2px; }

.umenu-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 0; }
.umenu-col { padding: 14px 16px; min-width: 0; }
.umenu-col + .umenu-col { border-left: 1px solid var(--border); }
.umenu-col h4 {
  display: flex; align-items: center; gap: 7px; margin: 0 0 10px;
  font-size: .74rem; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-3);
}
@media (max-width: 560px) {
  .umenu-cols { grid-template-columns: 1fr; }
  .umenu-col + .umenu-col { border-left: 0; border-top: 1px solid var(--border); }
}

.umenu-perms { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; }
.umenu-perms li {
  display: flex; align-items: center; gap: 7px;
  font-size: .8rem; color: var(--text-2);
}
.umenu-perms i.fi { color: var(--ok); }
.umenu-note { margin: 9px 0 0; font-size: .75rem; color: var(--text-3); line-height: 1.55; }

.umenu-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 9px; border-radius: var(--r-sm);
  color: inherit; text-decoration: none; transition: background .12s;
}
.umenu-item:hover { background: var(--accent-soft); text-decoration: none; }
.umenu-item i.fi { color: var(--text-3); flex: 0 0 16px; }
.umenu-item:hover i.fi { color: var(--accent); }
.umenu-item span { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.umenu-item b     { font-size: .82rem; font-weight: 500; }
.umenu-item small { font-size: .72rem; color: var(--text-3); }

.umenu-lang {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 16px; border-top: 1px solid var(--border); font-size: .74rem;
}
.umenu-lang .muted { display: inline-flex; align-items: center; gap: 6px; }
.langsw { display: inline-flex; border: 1px solid var(--border); border-radius: 7px; overflow: hidden; }
.langsw a {
  padding: 4px 11px; font-size: .74rem; line-height: 1.5; color: var(--text-2);
  text-decoration: none; background: var(--surface); transition: background .12s, color .12s;
}
.langsw a + a { border-left: 1px solid var(--border); }
.langsw a:hover { background: var(--surface-2); color: var(--text); }
.langsw a.on { background: var(--accent); color: var(--accent-ink); font-weight: 600; }

.umenu-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 16px; border-top: 1px solid var(--border); background: var(--surface-2);
  font-size: .74rem;
}

/* ---------- Tom Select — ให้เข้ากับโทเคนของระบบ ---------- */
/* ไลบรารีมาพร้อมสีของตัวเอง ต้องทับด้วยตัวแปรธีม ไม่งั้นเปลี่ยนชุดสีแล้วดรอปดาวน์ไม่ตาม */
.ts-wrapper { min-width: 0; }
/* ต้องระบุ .input-active ด้วย — ไลบรารีตั้งพื้นขาวไว้ที่ .ts-wrapper.single.input-active
   ซึ่งจำเพาะกว่าของเราหนึ่งคลาส เลยชนะเฉพาะตอนช่องถูกโฟกัส (พื้นขาวแวบขึ้นมากลางธีมมืด) */
.ts-wrapper.single .ts-control,
.ts-wrapper.single.input-active .ts-control,
.ts-wrapper.single.full .ts-control,
.ts-wrapper .ts-control {
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm); color: var(--text);
  padding: var(--pad-y) 32px var(--pad-y) 11px;
  font-family: inherit; font-size: .88rem; min-height: 0;
  box-shadow: none; transition: border-color .12s, box-shadow .12s;
}
.ts-wrapper.focus .ts-control,
.ts-control:focus-within {
  border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring);
}
.ts-wrapper.disabled .ts-control { opacity: .55; background: var(--surface-sunk); }
.ts-control > input,
.ts-wrapper.single.input-active .ts-control > input {
  color: var(--text) !important; font-family: inherit; background: transparent !important;
}
.ts-control > input::placeholder { color: var(--text-3); }

/* ลูกศร — วาดเองให้ตรงกับ <select> เดิมของระบบ */
.ts-wrapper.single .ts-control::after {
  content: ''; position: absolute; right: 13px; top: 50%;
  width: 6px; height: 6px; margin-top: -4px;
  border-right: 1.6px solid var(--text-3); border-bottom: 1.6px solid var(--text-3);
  transform: rotate(45deg); transition: transform .15s, border-color .15s;
}
.ts-wrapper.single.dropdown-active .ts-control::after {
  transform: rotate(-135deg); margin-top: -1px; border-color: var(--accent);
}

.ts-dropdown {
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r); box-shadow: var(--shadow-lg);
  margin-top: 5px; overflow: hidden; color: var(--text);
}
.ts-dropdown .option {
  padding: 8px 12px; font-size: .86rem; color: var(--text-2);
  border-radius: 0; transition: background .1s, color .1s;
}
.ts-dropdown .active { background: var(--accent-soft); color: var(--accent); }
.ts-dropdown .selected,
.ts-dropdown .option[aria-selected="true"] { color: var(--text); font-weight: 500; }
.ts-dropdown .selected.active { background: var(--accent); color: var(--accent-ink); }
.ts-dropdown .optgroup-header {
  padding: 9px 12px 5px; font-size: .72rem; font-weight: 600;
  letter-spacing: .03em; text-transform: uppercase;
  color: var(--text-3); background: transparent; cursor: default;
}
.ts-dropdown .optgroup + .optgroup .optgroup-header { border-top: 1px solid var(--border); margin-top: 3px; }
.ts-dropdown .no-results { padding: 10px 12px; font-size: .84rem; color: var(--text-3); }
.ts-dropdown-content { max-height: 320px; }

/* ช่องค้นหาในดรอปดาวน์ (เปิดเฉพาะรายการยาว) */
.ts-dropdown .dropdown-input-wrap { padding: 8px; border-bottom: 1px solid var(--border); }
.ts-dropdown .dropdown-input {
  width: 100%; padding: 7px 10px; border-radius: var(--r-sm);
  border: 1px solid var(--border-strong); background: var(--surface-sunk);
  color: var(--text); font-family: inherit; font-size: .85rem;
}
.ts-dropdown .dropdown-input:focus { outline: none; border-color: var(--accent); }

.ts-wrapper .clear-button {
  color: var(--text-3); opacity: 0; transition: opacity .12s, color .12s;
  right: 30px; font-size: 1.1rem;
}
.ts-wrapper:hover .clear-button, .ts-wrapper.focus .clear-button { opacity: 1; }
.ts-wrapper .clear-button:hover { color: var(--crit); }

/* ในแถบเครื่องมือ/ฟอร์มกริด ต้องกว้างเต็มช่องเหมือน select เดิม */
.field .ts-wrapper, .toolbar .ts-wrapper { width: 100%; }

/* ตัวเลือกในกลุ่ม seg ที่เป็นลิงก์ (ใช้กับตัวเลือกภาษา ซึ่งต้องโหลดหน้าใหม่) */
.seg .segl {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 7px 16px; font-size: .82rem; color: var(--text-2); text-decoration: none;
  border-radius: 7px; transition: background .12s, color .12s;
}
.seg .segl:hover { color: var(--text); }
.seg .segl.on { background: var(--accent); color: var(--accent-ink); font-weight: 600; }

/* ตารางติ๊กสิทธิ์รายคน (หน้าผู้ใช้) */
.permgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 2px 14px; }
.permrow { align-items: flex-start; padding: 7px 9px; border-radius: 8px; border: 1px solid transparent; }
.permrow:hover { background: var(--surface-2); }
.permrow.added   { border-color: color-mix(in oklab, var(--ok) 45%, transparent); background: color-mix(in oklab, var(--ok) 7%, transparent); }
.permrow.removed { border-color: color-mix(in oklab, var(--crit) 40%, transparent); background: color-mix(in oklab, var(--crit) 6%, transparent); }
.permrow .t { line-height: 1.45; }
.permrow .pill { margin-left: 6px; vertical-align: 1px; }
.permrow input:disabled + .t { opacity: .6; }
.pill.sm { font-size: .64rem; padding: 1px 6px; }

/* ฟอร์มอัปโหลดเฟิร์มแวร์ */
.fwup { margin: 4px 0 18px; padding: 14px; border: 1px dashed var(--border); border-radius: 10px; background: var(--surface-2); }
.fwup input[type=file] { width: 100%; font-size: .84rem; }

/* ---------- กล่องฟอร์มแบบ modal ---------- */
/* ฟอร์มเพิ่ม/แก้ไขเคยวางต่อท้ายหน้า ผู้ใช้ต้องเลื่อนผ่านตารางทั้งตารางไปหาเอง
   และเมื่อกด "แก้ไข" ก็ไม่เห็นว่าอะไรเปลี่ยน — ย้ายมาเป็นกล่องซ้อนหน้า
   งานที่กำลังทำจึงอยู่กลางจอเสมอ และปิดแล้วกลับมาที่รายการเดิม */
body.dlg-lock { overflow: hidden; }

.dlg-back {
  position: fixed; inset: 0; z-index: 210;
  background: color-mix(in srgb, oklch(12% .01 var(--h)) 62%, transparent);
  backdrop-filter: blur(3px);
  display: grid; place-items: start center; padding: 26px 20px;
  overflow-y: auto; overscroll-behavior: contain;
  opacity: 0; transition: opacity .16s ease;
}
.dlg-back.on { opacity: 1; }
.dlg-back[hidden] { display: none; }

.dlg {
  width: min(var(--dlg-w, 900px), 100%);
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; max-height: calc(100vh - 52px);
  transform: translateY(10px) scale(.99); transition: transform .16s ease;
}
.dlg-back.on .dlg { transform: none; }
.dlg.narrow { --dlg-w: 540px; }
.dlg.wide   { --dlg-w: 1080px; }

.dlg-head {
  display: flex; align-items: center; gap: 12px; flex: 0 0 auto;
  padding: 15px 18px; border-bottom: 1px solid var(--border);
}
.dlg-head h2 { font-family: var(--font-display); font-weight: 600; font-size: 1rem; margin: 0; }
.dlg-head .sub { font-size: .78rem; color: var(--text-3); margin-top: 2px; }
.dlg-x {
  margin-left: auto; flex: 0 0 30px; width: 30px; height: 30px;
  display: grid; place-items: center; cursor: pointer;
  background: transparent; border: 1px solid transparent; border-radius: var(--r-sm);
  color: var(--text-3); font-size: 1.15rem; line-height: 1; padding: 0;
}
.dlg-x:hover { background: var(--surface-2); color: var(--text); border-color: var(--border); }

.dlg-body { padding: 18px; overflow-y: auto; flex: 1 1 auto; }
.dlg-body > :first-child { margin-top: 0; }
.dlg-body > :last-child  { margin-bottom: 0; }
.dlg-body fieldset:last-of-type { margin-bottom: 0; }

/* ปุ่มล่างของกล่องไม่ใช้ .form-actions เพราะอันนั้น sticky ด้วย margin ลบของการ์ด */
.dlg-foot {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap; flex: 0 0 auto;
  padding: 13px 18px; background: var(--surface-2); border-top: 1px solid var(--border);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}
.dlg-foot .help, .dlg-foot .spacer { margin-left: auto; }

@media (prefers-reduced-motion: reduce) { .dlg-back, .dlg { transition: none; } }
@media (max-width: 640px) {
  .dlg-back { padding: 0; place-items: stretch; }
  .dlg { max-height: 100dvh; min-height: 100dvh; border: 0; border-radius: 0; }
  .dlg-foot { border-radius: 0; }
}

/* ---------- ตั้งค่าระบบ: แบรนด์ · Google · แหล่งข้อมูล ---------- */
/* โลโก้ที่ผู้ใช้อัปโหลดมีสัดส่วนไม่แน่นอน — บังคับความสูงแล้วปล่อยความกว้างตามจริง
   ไม่งั้นโลโก้แนวนอนยาว ๆ จะดันชื่อระบบตกบรรทัด */
/* โลโก้ยืนเดี่ยวจึงกินความกว้างของแถบได้เต็ม และสูงกว่าตอนวางคู่ชื่อได้ */
.side-brand.has-logo { justify-content: flex-start; padding: 14px 18px; }
.side-logo { height: 34px; max-width: 100%; object-fit: contain; object-position: left center; flex: 1 1 auto; min-width: 0; }
/* แถบกว้างเต็ม: โชว์โลโก้ · แถบย่อ: โชว์อักษรย่อ เพราะโลโก้แนวนอนหดแล้วอ่านไม่ออก */
.side-brand.has-logo > .side-mark { display: none; }
.app.nav-collapsed .side-brand.has-logo > .side-mark { display: grid; }
.app.nav-collapsed .side-brand.has-logo > .side-logo { display: none; }
.auth-brand.has-logo { display: block; }
.auth-logo { height: 44px; max-width: 100%; object-fit: contain; object-position: left center; }

.brand-preview { display: flex; align-items: center; gap: 12px; }
.brand-preview .brand-mark { flex: 0 0 auto; display: grid; place-items: center; }
.brand-preview img { height: 38px; max-width: 150px; object-fit: contain; }
.brand-preview .side-mark { width: 38px; height: 38px; flex-basis: 38px; font-size: 1rem; border-radius: 9px; }

/* คู่ ชื่อ–ค่า แบบสรุปในการ์ด — เบากว่า dl.kv ที่ใช้ในหน้ารายละเอียด */
.kv > div {
  display: flex; align-items: baseline; gap: 12px;
  padding: 8px 0; border-top: 1px solid var(--border-soft, var(--border));
}
.kv > div:first-child { border-top: 0; padding-top: 0; }
.kv > div > span { flex: 0 0 40%; font-size: .8rem; color: var(--text-3); }
.kv > div > b { font-weight: 600; font-size: .86rem; min-width: 0; overflow-wrap: anywhere; }

/* ปุ่ม Google ต้องดูเป็นของ Google ไม่ใช่ปุ่มธีมเรา — คนมองหาสีและโลโก้ที่คุ้นตา */
.auth-or {
  display: flex; align-items: center; gap: 12px;
  margin: 16px 0; font-size: .76rem; color: var(--text-3);
}
.auth-or::before, .auth-or::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.btn.gbtn {
  width: 100%; justify-content: center; gap: 10px;
  background: var(--surface); color: var(--text); border: 1px solid var(--border-strong);
  font-weight: 600;
}
.btn.gbtn:hover { background: var(--surface-2); }

/* ---------- ช่องเลือกไฟล์แบบลากมาวาง ---------- */
/* input จริงยังอยู่ครบ แค่โปร่งใสและขยายเต็มกรอบ — คลิก ลากวาง และโฟกัสด้วยคีย์บอร์ด
   จึงเป็นพฤติกรรมของเบราว์เซอร์เอง ไม่ได้เขียนเลียนแบบขึ้นมาใหม่ */
.drop {
  position: relative; display: grid; place-items: center;
  min-height: 104px; padding: 16px 14px; text-align: center;
  border: 1.5px dashed var(--border-strong); border-radius: var(--r);
  background: var(--surface-2); color: var(--text-2);
  transition: border-color .14s, background .14s;
}
.drop input[type=file] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer;
}
.drop:hover { border-color: var(--accent); }
.drop.over  { border-color: var(--accent); background: var(--accent-soft); }
.drop:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }

.drop-idle, .drop-picked { display: grid; gap: 5px; place-items: center; }
/* display: grid มีน้ำหนักมากกว่า [hidden] ที่เบราว์เซอร์ตั้งให้ — ต้องสั่งซ่อนเอง
   ไม่งั้นทั้งสองสถานะจะโผล่พร้อมกัน */
.drop-idle[hidden], .drop-picked[hidden] { display: none; }
.drop-picked { grid-template-columns: auto minmax(0,1fr) auto; gap: 10px; width: 100%; }
.drop-ic { color: var(--text-3); }
.drop.over .drop-ic, .drop-picked .drop-ic { color: var(--accent); }
.drop-t { font-size: .86rem; }
.drop-picked .drop-t { text-align: left; min-width: 0; }
.drop-name {
  display: block; font-weight: 600; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.drop-size { font-family: var(--font-mono); font-size: .74rem; color: var(--text-3); }
.drop-meta { font-family: var(--font-mono); font-size: .7rem; color: var(--text-3); letter-spacing: .04em; }

/* ปุ่มเอาไฟล์ออกต้องอยู่เหนือ input ที่คลุมทั้งกรอบ ไม่งั้นคลิกแล้วเปิดหน้าต่างเลือกไฟล์แทน */
.drop-x {
  position: relative; z-index: 2; flex: 0 0 26px; width: 26px; height: 26px;
  display: grid; place-items: center; cursor: pointer; padding: 0;
  background: transparent; border: 1px solid transparent; border-radius: var(--r-sm);
  color: var(--text-3); font-size: 1.1rem; line-height: 1;
}
.drop-x:hover { background: var(--surface); border-color: var(--border); color: var(--crit); }

/* ลากไฟล์มาวางผิดที่ เบราว์เซอร์จะเปิดไฟล์นั้นทับหน้าเว็บและงานที่กรอกไว้หายหมด
   จึงบล็อกการวางนอกกรอบไว้ แล้วบอกให้เห็นว่าต้องวางตรงไหน */
body.drag-on .drop { border-color: var(--accent); }

/* ---------- สวิตช์เปิด/ปิดชั้นข้อมูล ---------- */
/* ใช้กับตัวควบคุมที่มีผลทันทีที่กด (เช่นชั้นในฉาก 3 มิติ) — ไม่ใช้กับช่องติ๊กในฟอร์ม
   ที่ต้องกดบันทึกก่อนถึงจะมีผล เพราะรูปสวิตช์สื่อว่า "เปลี่ยนแล้วเดี๋ยวนี้"
   input จริงยังอยู่ครบ แค่ซ่อนไว้ — โฟกัสด้วยคีย์บอร์ดและ screen reader จึงยังทำงานปกติ */
.switch {
  display: inline-flex; align-items: center; gap: 9px;
  cursor: pointer; user-select: none; position: relative;
}
.switch > input {
  position: absolute; opacity: 0; width: 0; height: 0; margin: 0;
}
.switch .sw {
  flex: 0 0 30px; width: 30px; height: 17px; border-radius: 999px;
  background: var(--surface-sunk); border: 1px solid var(--border-strong);
  position: relative; transition: background .16s ease, border-color .16s ease;
}
.switch .sw::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--text-3);
  transition: transform .16s ease, background .16s ease;
}
.switch .t { font-size: .84rem; color: var(--text-3); transition: color .16s ease; }

.switch > input:checked + .sw { background: var(--accent); border-color: var(--accent); }
.switch > input:checked + .sw::after { transform: translateX(13px); background: var(--accent-ink); }
.switch > input:checked ~ .t { color: var(--text); font-weight: 500; }
.switch:hover .sw { border-color: var(--accent); }
.switch > input:focus-visible + .sw { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ชั้นที่ยังไม่มีข้อมูลต้องดูออกว่ากดไม่ได้ ไม่ใช่ปล่อยให้กดแล้วไม่เกิดอะไร */
.switch:has(> input:disabled) { cursor: not-allowed; }
.switch > input:disabled + .sw { opacity: .4; }
.switch > input:disabled ~ .t { opacity: .45; }

/* ---------- แถบเลื่อน ---------- */
/* ส่วนที่เลือกแล้วถูกไล่สีตาม --p ที่ JS อัปเดตให้ — เบราว์เซอร์ตระกูล WebKit
   ไม่มีแนวคิด "ส่วนที่เต็มแล้ว" ในตัว ต่างจาก Firefox ที่มี ::-moz-range-progress */
input[type=range] {
  -webkit-appearance: none; appearance: none;
  height: 18px; background: transparent; cursor: pointer; margin: 0;
  --p: 0%;
}
input[type=range]::-webkit-slider-runnable-track {
  height: 4px; border-radius: 999px;
  background: linear-gradient(to right, var(--accent) var(--p), var(--border) var(--p));
}
input[type=range]::-moz-range-track { height: 4px; border-radius: 999px; background: var(--border); }
input[type=range]::-moz-range-progress { height: 4px; border-radius: 999px; background: var(--accent); }

input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 14px; height: 14px; margin-top: -5px; border-radius: 50%;
  background: var(--surface); border: 2px solid var(--accent);
  box-shadow: var(--shadow-sm); transition: transform .12s ease;
}
input[type=range]::-moz-range-thumb {
  width: 14px; height: 14px; border-radius: 50%; border: 2px solid var(--accent);
  background: var(--surface); box-shadow: var(--shadow-sm);
}
input[type=range]:hover::-webkit-slider-thumb { transform: scale(1.12); }
input[type=range]:hover::-moz-range-thumb { transform: scale(1.12); }
input[type=range]:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--accent); outline-offset: 2px; }
input[type=range]:focus-visible::-moz-range-thumb { outline: 2px solid var(--accent); outline-offset: 2px; }
input[type=range]:disabled { opacity: .45; cursor: not-allowed; }

@media (prefers-reduced-motion: reduce) {
  .switch .sw, .switch .sw::after, .switch .t, input[type=range]::-webkit-slider-thumb { transition: none; }
}

/* เครดิตภาพถ่าย — เงื่อนไขการใช้ของแหล่งภาพส่วนใหญ่บังคับให้แสดงที่มา
   วางต่อจากบรรทัดสถานะ ตัดท้ายเมื่อยาวเกิน แต่ยังอ่านครบได้จาก title */
.viz-credit {
  font-size: .68rem; letter-spacing: .01em; opacity: .8;
  max-width: 40ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- ฉาก 3 มิติแบบเต็มจอ ---------- */
/* การ์ดทั้งใบเข้าเต็มจอ แถบสวิตช์ชั้นข้อมูลจึงยังอยู่ให้กดได้
   ผืนผ้าใบต้องยืดเต็มพื้นที่ที่เหลือ ไม่ใช่ค้างที่ความสูงเดิมที่ตั้งไว้ inline */
.card.is-full {
  position: fixed; inset: 0; z-index: 300;
  display: flex; flex-direction: column;
  margin: 0; border: 0; border-radius: 0;
  background: var(--surface);
}
.card.is-full > #viz { flex: 1 1 auto; height: auto !important; min-height: 0; }
/* กันหน้าข้างหลังเลื่อนตอนที่ฉากขยายเต็มหน้าต่าง */
body.viz-full { overflow: hidden; }

/* ป๊อปอัปของ <select> วาดโดยระบบปฏิบัติการ สั่งสีเองไม่ได้ — บอกได้แค่ว่าให้ใช้ชุดสีไหน
   ถ้าไม่บอก โหมดมืดจะได้กล่องขาวไฮไลต์น้ำเงินสดตัดกับหน้าที่เหลือ
   ปกติ Tom Select ครอบให้อยู่แล้ว ตรงนี้เผื่อกรณีที่มันโหลดไม่ขึ้นหรือ init ไม่ผ่าน */
select, input, textarea { color-scheme: inherit; }
