/* ops-center — ชุดหน้าตาร่วมของทุกหน้า
 *
 * เดิม token สีอยู่ในทุกไฟล์ ไฟล์ละชุด แก้ทีต้องไล่ห้าที่แล้วก็เพี้ยนกันจนได้
 * ที่นี่มีชุดเดียว หน้าไหนต้องการอะไรเฉพาะตัวค่อยเขียนทับสั้น ๆ ในหน้านั้น
 *
 * หลักที่ยึด: สัดส่วนมาจากสเกลคงที่ (ระยะ ขนาดตัวอักษร ความโค้ง) ไม่ใช่ตัวเลขสุ่ม
 * ลูกเล่นมีได้แต่ต้องเงียบ — ไล่เฉดบาง ๆ เงาอ่อน ขยับ 150ms ไม่มีอะไรกระโดดใส่หน้า
 */

/* ---------- token ---------- */
:root{
  /* พื้นหลังไล่จากหลังสุดมาหน้าสุด: หน้าเว็บ → แผง → แถบในแผง */
  --bg:#f4f7f9; --bg2:#eaeff4;
  --panel:#fff; --panel2:#eef2f6; --panel3:#f7f9fb;
  --ink:#0f1f2d; --ink2:#2c3f52; --muted:#61748a;
  --line:#dbe3ec; --line2:#c6d2df;

  /* สีเน้นเลือกได้ — ค่าจริงอยู่ในบล็อก [data-accent] ท้ายไฟล์ ตรงนี้แค่ชี้ว่า
     โหมดสว่างใช้ชุด -l  ถ้าไม่แยกแบบนี้ ทุกสี × สองโหมด = ต้องเขียนบล็อกละสามรอบ */
  --accent:var(--a-l); --accent2:var(--a2-l);
  --accent-soft:var(--as-l); --accent-line:var(--al-l); --accent-glow:var(--ag-l);
  --green:#0f7047; --green-soft:#d8f0e4; --green-line:#a3d7bf;
  --red:#9a4128; --red-soft:#f8e3da; --red-line:#e4b7a5;
  --amber:#805c0a; --amber-soft:#f8ecd0; --amber-line:#e2c88a;

  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
  --sans:system-ui,-apple-system,"Segoe UI","Noto Sans Thai",sans-serif;

  /* ระยะทั้งระบบมาจากแปดชุดนี้เท่านั้น */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px; --s7:48px;
  --r1:8px; --r2:11px; --r3:15px; --r4:20px;

  --sh1:0 1px 2px rgba(16,34,51,.05), 0 1px 1px rgba(16,34,51,.03);
  --sh2:0 4px 14px rgba(16,34,51,.08), 0 1px 3px rgba(16,34,51,.05);
  --sh3:0 18px 44px rgba(16,34,51,.18), 0 3px 10px rgba(16,34,51,.09);

  --on-accent:var(--oa-l);
  --tap:38px;
  --fast:.15s cubic-bezier(.4,0,.2,1);
  --head-h:56px;
}
/* ชุดสีของโหมดมืด เขียนซ้ำสองที่โดยตั้งใจ — CSS ล้วนแชร์บล็อกข้ามมีเดียคิวรีไม่ได้
 *  1. ในมีเดียคิวรี: สำหรับคนที่ปล่อยให้ตามเครื่อง และยังทำงานแม้จาวาสคริปต์ไม่โหลด
 *  2. ในตัวเลือก [data-theme]: สำหรับคนที่กดสลับเอง ซึ่งต้องชนะค่าของเครื่องทั้งสองทาง
 * :not([data-theme="light"]) คือจุดที่ทำให้ "เครื่องมืด แต่ฉันเลือกสว่าง" ทำงานได้
 */
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    /* โหมดมืดสีหลักสว่างขึ้นเพื่อให้อ่านบนพื้นดำได้ พอเอาไปเป็นพื้นปุ่มแล้ว
       ตัวอักษรขาวจะเหลือคอนทราสต์ราว 1.9:1 ซึ่งอ่านไม่ออก — สลับเป็นตัวอักษรเข้มแทน */
    --on-accent:var(--oa-d);
    --bg:#0b131b; --bg2:#0f1925;
    --panel:#141f2b; --panel2:#1c2937; --panel3:#18242f;
    --ink:#e2eaf2; --ink2:#c2d0de; --muted:#8fa2b6;
    --line:#26354a; --line2:#33465e;

    --accent:var(--a-d); --accent2:var(--a2-d);
    --accent-soft:var(--as-d); --accent-line:var(--al-d); --accent-glow:var(--ag-d);
    --green:#52b98a; --green-soft:#0e2a20; --green-line:#1d4c39;
    --red:#dd8b6b; --red-soft:#33201a; --red-line:#5c392c;
    --amber:#dcb160; --amber-soft:#2d2415; --amber-line:#524125;

    --sh1:0 1px 2px rgba(0,0,0,.3);
    --sh2:0 4px 14px rgba(0,0,0,.36), 0 1px 3px rgba(0,0,0,.3);
    --sh3:0 18px 44px rgba(0,0,0,.5), 0 3px 10px rgba(0,0,0,.35);
  }
}
:root[data-theme="dark"]{
  /* โหมดมืดสีหลักสว่างขึ้นเพื่อให้อ่านบนพื้นดำได้ พอเอาไปเป็นพื้นปุ่มแล้ว
     ตัวอักษรขาวจะเหลือคอนทราสต์ราว 1.9:1 ซึ่งอ่านไม่ออก — สลับเป็นตัวอักษรเข้มแทน */
  --on-accent:var(--oa-d);
  --bg:#0b131b; --bg2:#0f1925;
  --panel:#141f2b; --panel2:#1c2937; --panel3:#18242f;
  --ink:#e2eaf2; --ink2:#c2d0de; --muted:#8fa2b6;
  --line:#26354a; --line2:#33465e;

  --accent:var(--a-d); --accent2:var(--a2-d);
  --accent-soft:var(--as-d); --accent-line:var(--al-d); --accent-glow:var(--ag-d);
  --green:#52b98a; --green-soft:#0e2a20; --green-line:#1d4c39;
  --red:#dd8b6b; --red-soft:#33201a; --red-line:#5c392c;
  --amber:#dcb160; --amber-soft:#2d2415; --amber-line:#524125;

  --sh1:0 1px 2px rgba(0,0,0,.3);
  --sh2:0 4px 14px rgba(0,0,0,.36), 0 1px 3px rgba(0,0,0,.3);
  --sh3:0 18px 44px rgba(0,0,0,.5), 0 3px 10px rgba(0,0,0,.35);
}
/* ตอนสลับธีมให้ไล่สีแทนที่จะกระพริบ แต่เฉพาะพื้นหลังกับเส้น ไม่รวมตัวอักษร
   เพราะถ้าไล่ทุกอย่างพร้อมกันจะเห็นเป็นอาการค้างมากกว่าความลื่น */
:root.swap, :root.swap body, :root.swap .panel, :root.swap .card,
:root.swap .site, :root.swap header, :root.swap .rail{
  transition:background-color .22s ease, border-color .22s ease;
}

*{box-sizing:border-box}
/* [hidden] ของเบราว์เซอร์คือ display:none ที่ความจำเพาะต่ำสุด คลาสไหนที่ตั้ง display
   เอาไว้ (เช่น .bulk{display:flex}) จะชนะมัน แล้วของที่สั่งซ่อนก็ยังโผล่อยู่
   เจอมาแล้วกับแถบคำสั่งที่โชว์ "0 รายการที่เลือก" ทั้งที่ยังไม่ได้เลือกอะไร */
[hidden]{display:none!important}
html{-webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--bg); color:var(--ink);
  font:15px/1.6 var(--sans);
  /* พื้นหลังมีไล่เฉดบาง ๆ ให้ไม่แบนทื่อ แต่ไม่ถึงกับเห็นเป็นลาย */
  background-image:radial-gradient(900px 420px at 92% -8%, var(--bg2), transparent 62%);
  background-attachment:fixed;
  -webkit-font-smoothing:antialiased;
}
::selection{background:var(--accent-soft);color:var(--accent)}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline}

/* ทุกอย่างที่โฟกัสได้ต้องเห็นชัดว่าโฟกัสอยู่ — คนใช้คีย์บอร์ดล้วนต้องใช้หน้านี้ได้ */
:focus-visible{outline:2px solid var(--accent2);outline-offset:2px;border-radius:var(--r1)}

/* ---------- แถบหัว ---------- */
header{
  position:sticky; top:0; z-index:30;
  min-height:var(--head-h);
  padding:var(--s2) var(--s4);
  padding-top:max(var(--s2), env(safe-area-inset-top));
  display:flex; gap:var(--s3); align-items:center; flex-wrap:wrap;
  background:color-mix(in srgb, var(--panel) 86%, transparent);
  border-bottom:1px solid var(--line);
  box-shadow:var(--sh1);
}
@supports (backdrop-filter:blur(1px)){
  header{backdrop-filter:saturate(1.6) blur(12px)}
}
header h1{
  margin:0; font-size:16px; font-weight:650; letter-spacing:-.015em;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.spacer{flex:1}
/* กลุ่มปุ่มขวาของแถบหัว — รวมเป็นก้อนเดียวเพื่อให้ตกลงแถวสองพร้อมกัน ไม่ใช่ทีละปุ่ม */
.row-2{display:flex;gap:6px;align-items:center;flex-wrap:wrap}

/* เครื่องหมายประจำระบบ — ตัวอักษรเดียวในสี่เหลี่ยมไล่เฉด ไม่ต้องมีไฟล์รูป */
.brand{display:flex;align-items:center;gap:10px;min-width:0}
.mark{
  width:26px;height:26px;flex:none;border-radius:var(--r1);
  background:linear-gradient(145deg, var(--accent2), var(--accent));
  color:var(--on-accent);font-size:13px;font-weight:800;letter-spacing:-.03em;
  display:grid;place-items:center;
  box-shadow:0 3px 10px var(--accent-glow);
  text-decoration:none;
}
a.mark:hover{text-decoration:none;filter:brightness(1.12)}

/* ---------- ตัวอักษร ---------- */
h2{
  font-size:12px; text-transform:uppercase; letter-spacing:.07em;
  color:var(--muted); margin:0 0 var(--s3); font-weight:700;
}
.dg{color:var(--muted);font-size:12.5px}
.mono{font-family:var(--mono);font-size:.93em}
.num{font-variant-numeric:tabular-nums}

main{padding:var(--s5) var(--s4) var(--s7);max-width:1180px;margin:0 auto}
main.wide{max-width:1320px}

/* ---------- ปุ่ม ---------- */
button{
  font:inherit; font-weight:550;
  min-height:var(--tap); padding:6px var(--s3);
  border-radius:var(--r1); cursor:pointer;
  border:1px solid var(--line); background:var(--panel); color:var(--ink2);
  box-shadow:var(--sh1);
  transition:border-color var(--fast), background var(--fast),
             box-shadow var(--fast), transform var(--fast), color var(--fast);
}
button:hover:not(:disabled){border-color:var(--line2);color:var(--ink);box-shadow:var(--sh2)}
button:active:not(:disabled){transform:translateY(1px);box-shadow:var(--sh1)}
button:disabled{opacity:.45;cursor:default;box-shadow:none}

button.go{
  background:linear-gradient(180deg, var(--accent2), var(--accent));
  border-color:transparent; color:var(--on-accent);
  box-shadow:0 3px 12px var(--accent-glow);
}
button.go:hover:not(:disabled){filter:brightness(1.07);color:var(--on-accent)}
button.warn{background:var(--amber-soft);border-color:var(--amber-line);color:var(--amber)}
button.danger{background:var(--panel);border-color:var(--red-line);color:var(--red)}
button.danger:hover:not(:disabled){background:var(--red-soft);color:var(--red)}
button.ghost{background:transparent;border-color:transparent;box-shadow:none;color:var(--muted)}
button.ghost:hover:not(:disabled){background:var(--panel2);color:var(--ink)}
button.sm{min-height:30px;padding:3px 10px;font-size:12.5px}
button.block{width:100%}

/* ---------- ช่องกรอก ---------- */
input,select,textarea{
  font:inherit; min-height:var(--tap); padding:7px 11px;
  border-radius:var(--r1); border:1px solid var(--line);
  background:var(--panel3); color:var(--ink);
  transition:border-color var(--fast), background var(--fast), box-shadow var(--fast);
}
input:hover,select:hover{border-color:var(--line2)}
input:focus,select:focus,textarea:focus{
  outline:none; border-color:var(--accent2); background:var(--panel);
  box-shadow:0 0 0 3px var(--accent-glow);
}
input::placeholder{color:var(--muted);opacity:.75}
/* ช่องติ๊กกับปุ่มวงกลมต้องหลุดจากกฎความสูง/ความกว้างของช่องกรอก — ไม่งั้นมันจะ
   ยืดเต็มบรรทัดจนข้อความข้าง ๆ ถูกบีบหายไป (เจอมาแล้วทั้งกับ checkbox และ radio) */
input[type=checkbox],input[type=radio]{min-height:0;width:16px;height:16px;
  accent-color:var(--accent)}
label.check{display:inline-flex;align-items:center;gap:6px;cursor:pointer}

/* ---------- แผง ---------- */
.panel,.card{
  background:var(--panel); border:1px solid var(--line);
  border-radius:var(--r3); box-shadow:var(--sh1);
}
.panel{padding:var(--s4) var(--s4) var(--s3);margin-bottom:var(--s4)}
.card{padding:var(--s4) var(--s5);margin-bottom:var(--s4)}
.panel h2{display:flex;align-items:baseline;gap:var(--s2);flex-wrap:wrap}

.toolbar{display:flex;gap:var(--s2);align-items:center;flex-wrap:wrap;margin-bottom:var(--s3)}
.toolbar input[type=search]{min-width:170px;flex:1}
/* ตัวที่ทำหน้าที่บอกสถานะ (เช่น "เลือกไว้ 3 คน") ไปชิดขวาเสมอ ไม่ใช่เบียดติดปุ่ม */
.toolbar .right{margin-left:auto}
/* แถวปุ่มท้ายแผง — มีเส้นคั่นให้รู้ว่าจบส่วนกรอกแล้ว */
.toolbar.foot{margin:var(--s3) 0 0;padding-top:var(--s3);
  border-top:1px solid var(--line);justify-content:flex-end}
.toolbar.foot .left{margin-right:auto}

/* ---------- ป้ายสถานะ ---------- */
.pill{
  display:inline-flex; align-items:center; gap:5px;
  padding:3px 10px; border-radius:999px;
  font-size:11.5px; font-weight:700; line-height:1.5;
  border:1px solid transparent; white-space:nowrap;
}
.pill.ok{background:var(--green-soft);color:var(--green);border-color:var(--green-line)}
.pill.bad{background:var(--red-soft);color:var(--red);border-color:var(--red-line)}
.pill.warn{background:var(--amber-soft);color:var(--amber);border-color:var(--amber-line)}
.pill.new{background:var(--accent-soft);color:var(--accent);border-color:var(--accent-line)}
.pill.flat{background:var(--panel2);color:var(--muted);border-color:var(--line)}
.pill.admin{background:var(--accent-soft);color:var(--accent);border-color:var(--accent-line)}
.pill.read{background:var(--panel2);color:var(--muted);border-color:var(--line)}
.pill.env{background:var(--amber-soft);color:var(--amber);border-color:var(--amber-line)}

/* จุดสถานะ — ของที่ยังมีชีวิตจะเต้นเบา ๆ ให้กวาดตาเจอโดยไม่ต้องอ่าน */
.pill.ok::before,.pill.bad::before,.pill.flat::before{
  content:"";width:6px;height:6px;border-radius:999px;background:currentColor;flex:none;
}
.pill.ok::before{animation:beat 2.4s ease-in-out infinite}
@keyframes beat{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.82)}}

/* ---------- ตาราง ---------- */
table{width:100%;border-collapse:collapse}
th,td{text-align:left;padding:10px var(--s2);border-bottom:1px solid var(--line);
  vertical-align:top}
th{
  font-size:11px; color:var(--muted); text-transform:uppercase;
  letter-spacing:.06em; font-weight:700; padding-top:0;
}
.scroll th{position:sticky;top:0;background:var(--panel);z-index:1}
tbody tr{transition:background var(--fast)}
tbody tr:hover{background:var(--panel3)}
tr:last-child td{border-bottom:none}
.nm{font-weight:650;letter-spacing:-.01em}
.acts{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}
.empty{text-align:center;color:var(--muted);padding:var(--s5) var(--s4)}
.scroll{max-height:min(66vh,720px);overflow:auto;border-radius:var(--r1)}
/* ตารางที่บีบไม่ลงจริง ๆ ให้เลื่อนในกรอบตัวเอง ไม่ใช่ดันทั้งหน้าให้เลื่อนข้าง */
.xscroll{
  overflow-x:auto; -webkit-overflow-scrolling:touch; max-width:100%;
  background:
    linear-gradient(90deg, var(--panel) 30%, transparent) left / 24px 100% no-repeat,
    linear-gradient(270deg, var(--panel) 30%, transparent) right / 24px 100% no-repeat,
    radial-gradient(farthest-side at 0 50%, rgba(16,34,51,.13), transparent)
      left / 12px 100% no-repeat,
    radial-gradient(farthest-side at 100% 50%, rgba(16,34,51,.13), transparent)
      right / 12px 100% no-repeat;
  background-attachment:local,local,scroll,scroll;
}

/* ---------- ข้อความแจ้ง ---------- */
.msg{border-radius:var(--r2);padding:10px var(--s3);font-size:13.5px;
  margin-bottom:var(--s4);border:1px solid transparent}
.msg.err,.err{background:var(--red-soft);color:var(--red);border-color:var(--red-line)}
.msg.ok,.ok-box{background:var(--green-soft);color:var(--green);border-color:var(--green-line)}
.banner{background:var(--amber-soft);color:var(--amber);border:1px solid var(--amber-line);
  border-radius:var(--r2);padding:10px var(--s4);margin-bottom:var(--s4);font-size:13.5px}
/* .banner เฉย ๆ คือสีเหลือง (เตือน) — .ok คือเรื่องที่สำเร็จแล้ว .warn คือของที่พังอยู่ตอนนี้ */
.banner.ok{background:var(--green-soft);color:var(--green);border-color:var(--green-line)}
.banner.warn{background:var(--red-soft);color:var(--red);border-color:var(--red-line)}
.note{color:var(--muted);font-size:12.5px;margin:0 0 var(--s3)}

/* ---------- กล่องซ้อน ---------- */
dialog{
  border:1px solid var(--line); border-radius:var(--r4); padding:0;
  max-width:720px; width:min(94vw,720px);
  background:var(--panel); color:var(--ink); box-shadow:var(--sh3);
}
dialog::backdrop{background:rgba(9,18,28,.5)}
@supports (backdrop-filter:blur(1px)){dialog::backdrop{backdrop-filter:blur(3px)}}
dialog[open]{animation:pop .18s cubic-bezier(.2,.9,.3,1.2)}
@keyframes pop{from{opacity:0;transform:translateY(10px) scale(.985)}}
.dlg-h{padding:var(--s4) var(--s5) var(--s3);border-bottom:1px solid var(--line)}
.dlg-h h3{margin:0 0 3px;font-size:16.5px;font-weight:650;letter-spacing:-.015em}
.dlg-b{padding:var(--s4) var(--s5) var(--s5)}
menu{display:flex;gap:var(--s2);justify-content:flex-end;margin:0;
  padding:var(--s3) var(--s5);border-top:1px solid var(--line);
  background:var(--panel3);border-radius:0 0 var(--r4) var(--r4);flex-wrap:wrap}

/* ---------- ของเฉพาะหน้าไซต์ ---------- */
pre.log{
  margin:0;padding:var(--s3);background:var(--panel2);border:1px solid var(--line);
  border-radius:var(--r2);font-family:var(--mono);font-size:12px;line-height:1.55;
  white-space:pre-wrap;overflow-wrap:anywhere;max-height:52vh;overflow:auto;
}
.ev-k{font-family:var(--mono);font-size:12px;font-weight:650;width:34%;
  overflow-wrap:break-word}
.ev-v{font-family:var(--mono);font-size:12px;white-space:pre-wrap;overflow-wrap:anywhere;
  background:var(--panel2);border:1px solid var(--line);border-radius:7px;padding:6px 8px}
.ev-src{display:block;margin-top:3px;font-size:11px;font-weight:400;color:var(--muted)}
.bar{height:6px;border-radius:999px;background:var(--panel2);overflow:hidden;
  margin-top:5px;max-width:190px;border:1px solid var(--line)}
.bar>i{display:block;height:100%;border-radius:999px;
  background:linear-gradient(90deg, var(--accent2), var(--accent));
  transition:width .3s ease}
#toast{
  position:fixed;left:var(--s3);right:var(--s3);
  bottom:max(var(--s4), env(safe-area-inset-bottom));
  max-width:540px;margin:0 auto;padding:12px var(--s4);
  border-radius:var(--r3);background:var(--panel);border:1px solid var(--line);
  box-shadow:var(--sh3);white-space:pre-wrap;display:none;z-index:50;
  animation:rise .2s cubic-bezier(.2,.9,.3,1.1);
}
@keyframes rise{from{opacity:0;transform:translateY(12px)}}
#toast.ok{border-color:var(--green-line);box-shadow:var(--sh3),
  inset 3px 0 0 var(--green)}
#toast.bad{border-color:var(--red-line);box-shadow:var(--sh3),
  inset 3px 0 0 var(--red)}

/* ---------- การ์ดไซต์ (หน้าแรก) ---------- */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(292px,1fr));gap:var(--s4)}
.site{
  position:relative;overflow:hidden;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r3);
  padding:var(--s4) var(--s5) var(--s4);text-align:left;cursor:pointer;
  display:block;width:100%;min-height:auto;font:inherit;color:inherit;
  box-shadow:var(--sh1);
  transition:border-color var(--fast), box-shadow var(--fast), transform var(--fast);
}
/* เส้นบางบนขอบบน โผล่ตอนชี้ — บอกว่ากดได้โดยไม่ต้องใส่ปุ่มเพิ่ม */
.site::after{
  content:"";position:absolute;inset:0 0 auto;height:2px;
  background:linear-gradient(90deg, var(--accent2), var(--accent));
  transform:scaleX(0);transform-origin:left;transition:transform .25s ease;
}
.site:hover{border-color:var(--line2);box-shadow:var(--sh2);transform:translateY(-2px)}
.site:hover::after{transform:scaleX(1)}
.site.off{cursor:default;opacity:.72;box-shadow:none}
.site.off:hover{border-color:var(--line);transform:none;box-shadow:none}
.site.off:hover::after{transform:scaleX(0)}
.name{font-size:17px;font-weight:700;letter-spacing:-.02em;margin-bottom:2px}
.row{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin-top:var(--s3)}
.stat{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s2);
  margin-top:var(--s4);padding-top:var(--s3);border-top:1px solid var(--line)}
.stat div{font-size:12px;color:var(--muted);line-height:1.35}
.stat b{display:block;font-size:22px;font-weight:650;color:var(--ink);line-height:1.25;
  font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.stat b.hot{color:var(--accent)}
.stat b.bad{color:var(--red)}

/* ---------- โครงร่างระหว่างโหลด ---------- */
/* "กำลังโหลด…" เป็นตัวหนังสือทำให้หน้ากระตุกตอนของจริงมาแทน อันนี้กินที่เท่าของจริง */
.skel{border-radius:var(--r3);border:1px solid var(--line);background:var(--panel);
  height:186px;position:relative;overflow:hidden}
.skel::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--panel2) 70%,transparent),
    transparent);
  transform:translateX(-100%);animation:sweep 1.4s infinite;
}
@keyframes sweep{to{transform:translateX(100%)}}

/* ---------- มือถือ ---------- */
@media (max-width:820px){
  :root{--tap:40px}
  main{padding:var(--s4) var(--s3) var(--s6)}
  .card{padding:var(--s4)}
  .panel{padding:var(--s3) var(--s3) var(--s2)}
  .dlg-h,.dlg-b,menu{padding-left:var(--s4);padding-right:var(--s4)}
  .hide-sm{display:none}
  .acts{justify-content:flex-start}
  th,td{padding:9px 6px}
  .grid{grid-template-columns:1fr;gap:var(--s3)}
  header{gap:var(--s2);padding:var(--s2) var(--s3)}
  header h1{font-size:15px}
}
@media (max-width:520px){
  /* ปุ่มในแถบหัวเรียงกันจนล้น — ให้แถวที่สองกว้างเต็มแทนที่จะบีบจนกดไม่โดน */
  header .row-2{width:100%}
  header .row-2 button{flex:1}
  header .row-2 button{flex:1}
  dialog{width:100vw;max-width:100vw;border-radius:var(--r4) var(--r4) 0 0;
    margin:auto 0 0;max-height:92vh}
  menu{border-radius:0}
}

/* นิ้วต้องกดโดน — เมาส์ไม่ต้องใหญ่ขนาดนั้น */
@media (pointer:coarse){
  button{min-height:42px}
  button.sm{min-height:34px}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important}
  .site:hover{transform:none}
}

/* พิมพ์ออกกระดาษ — ใช้ตอนแนบรายงาน */
@media print{
  header,button,.toolbar{display:none!important}
  body{background:#fff}
  .panel,.card,.site{box-shadow:none;border-color:#ccc;break-inside:avoid}
}

/* ---------- หน้าเข้าสู่ระบบ / ยืนยันอุปกรณ์ ---------- */
/* สองหน้านี้ไม่มีแถบหัว มีกล่องเดียวกลางจอ จึงจัดวางคนละแบบกับหน้าที่เหลือ */
body.center{
  min-height:100vh; min-height:100dvh;
  display:grid; place-items:center;
  padding:var(--s5) var(--s4);
  padding-bottom:max(var(--s5), env(safe-area-inset-bottom));
}
body.center .card{
  width:100%; max-width:392px; margin:0;
  padding:var(--s6) var(--s5) var(--s5);
  border-radius:var(--r4); box-shadow:var(--sh2);
}
body.center .mark{width:38px;height:38px;border-radius:var(--r2);font-size:17px;
  margin-bottom:var(--s4)}
body.center h1{margin:0 0 3px;font-size:21px;font-weight:700;letter-spacing:-.025em}
.sub{color:var(--muted);font-size:13.5px;margin:0 0 var(--s5)}
.who{font-size:13.5px;margin:0 0 var(--s5);color:var(--muted);
  background:var(--panel3);border:1px solid var(--line);border-radius:var(--r2);
  padding:9px var(--s3);overflow-wrap:anywhere}
.who b{color:var(--ink);font-weight:650}
body.center label{display:block;font-size:12.5px;color:var(--muted);margin-bottom:5px}
body.center input{width:100%;margin-bottom:var(--s4)}
body.center button{width:100%;padding:11px;font-weight:650;min-height:44px}
button.alt{background:var(--panel);color:var(--ink2);border-color:var(--line);
  font-weight:550;margin-top:var(--s2)}
button.alt:hover:not(:disabled){background:var(--panel2)}
.why{margin:var(--s5) 0 0;padding-top:var(--s4);border-top:1px solid var(--line);
  font-size:12.5px;color:var(--muted)}
.why ul{margin:var(--s2) 0 0;padding-left:18px}
.why li{margin-bottom:5px}

/* ---------- แถวฟอร์มในหน้าผู้ใช้ ---------- */
/* ฟอร์มเพิ่มของ — กริดคอลัมน์เท่ากัน ไม่ใช่ flex-wrap
   ของเดิมห่อบรรทัดตามความกว้างของแต่ละช่อง ผลคือแต่ละแถวมีจำนวนช่องไม่เท่ากัน
   ขอบซ้ายไม่ตรงกัน และปุ่มไปค้างอยู่ท้ายแถวไหนก็ได้ */
/* auto-fill ไม่ใช่ auto-fit — fit จะยุบคอลัมน์ที่ว่างแล้วยืดช่องที่เหลือจนเต็ม
   ฟอร์มที่มีสองช่องเลยกว้างคนละขนาดกับฟอร์มที่มีห้าช่อง ขอบซ้ายไม่ตรงกันสักฟอร์ม
   fill คงคอลัมน์ว่างไว้ ทุกฟอร์มจึงวางบนตารางเดียวกัน */
.add{display:grid;gap:var(--s3) var(--s4);align-items:end;
  grid-template-columns:repeat(auto-fill,minmax(200px,1fr))}
.add label{display:flex;flex-direction:column;gap:5px;font-size:12.5px;color:var(--muted);
  min-width:0}
/* ป้ายกำกับยาวได้สองบรรทัด ช่องกรอกจึงต้องชิดล่างของเซลล์ ขอบล่างถึงจะตรงกันทั้งแถว */
.add:has(label) label{align-self:end}
.add .wide{grid-column:span 2}
/* select กับ input สูงไม่เท่ากันโดยธรรมชาติ (33 กับ 36) พอชิดล่างแล้วขอบบนจะเหลื่อม
   กัน 3px บังคับความสูงให้เท่ากันไปเลย */
.add label input,.add label select,.add label textarea{width:100%}
.add label input,.add label select{height:var(--tap)}
/* ช่องติ๊กต้องคงขนาดเดิมและอยู่บรรทัดเดียวกับข้อความ — กฎสองบรรทัดบนบังคับให้ลูกของ
   label เต็มความกว้างและสูงเท่าช่องกรอก ซึ่งทำให้ checkbox กลายเป็นสี่เหลี่ยมขาว
   ใหญ่คร่อมข้อความที่ตกไปอยู่ข้างล่าง (เจอจริงที่กล่องมอบสิทธิ์ชั่วคราว) */
.add label.check{flex-direction:row;align-items:center;gap:6px}
.add label input[type=checkbox],.add label input[type=radio]{
  width:16px;height:16px;flex:0 0 auto}
/* ปุ่มลงมาอยู่บรรทัดของตัวเองชิดขวา — อยู่ปนกับช่องกรอกแล้วตาจะหาไม่เจอว่ากดตรงไหน */
.add button{grid-column:1/-1;justify-self:end;min-width:120px}
@media (max-width:760px){
  .add{grid-template-columns:1fr}
  .add .wide{grid-column:span 1}
  .add button{justify-self:stretch}
  /* จอแคบ ปุ่มสองปุ่มเบียดกันจนตัวนับหลุดไปคนละบรรทัดแบบไม่ตั้งใจ
     สั่งให้ตัวนับกินเต็มบรรทัดบนไปเลย แล้วปุ่มแบ่งครึ่งบรรทัดล่างเท่า ๆ กัน */
  .toolbar.foot .left{flex:1 0 100%;margin-right:0}
  .toolbar.foot button{flex:1}
}

/* ---------- บรรทัดอุปกรณ์ ---------- */
.dev{font-size:12.5px;color:var(--muted);padding:7px 0;
  display:flex;gap:var(--s2);align-items:center;flex-wrap:wrap;
  border-top:1px dashed var(--line)}
.dev:first-child{border-top:0}
.dev b{color:var(--ink);font-weight:650}
.dev .grow{flex:1;min-width:120px}

/* ---------- ของประกอบเล็ก ๆ ---------- */
.full{width:100%;margin:6px 0 10px}
.right{text-align:right}
.newer{color:var(--accent);font-weight:600}

/* เส้นคั่นก่อนข้อความอธิบายท้ายกล่อง — ไม่มีเส้นแล้วมันไปติดปุ่มจนอ่านเป็นก้อนเดียว */
body.center .note{margin:var(--s5) 0 0;padding-top:var(--s4);
  border-top:1px solid var(--line)}
/* อีเมลกับ digest ยาวเกินคอลัมน์บนจอแคบ ให้ตัดบรรทัดได้แทนที่จะดันตารางกว้าง */
td .mono,td.mono{overflow-wrap:anywhere}

/* ---------- แถบสรุปรวมหน้าแรก ---------- */
/* หน้าแรกมีแค่การ์ดไม่กี่ใบแล้วว่างทั้งจอ แถบนี้ตอบคำถามแรกที่ทุกคนถามตอนเปิดหน้า:
   ตอนนี้มีอะไรต้องรีบดูไหม — ใช้ข้อมูลที่โหลดมาอยู่แล้ว ไม่ได้ยิงเพิ่ม */
.sum{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s3);margin-bottom:var(--s5)}
.sum > div{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r2);
  padding:var(--s3) var(--s4);box-shadow:var(--sh1);
}
.sum b{display:block;font-size:24px;font-weight:650;letter-spacing:-.025em;
  line-height:1.2;font-variant-numeric:tabular-nums}
.sum span{font-size:12px;color:var(--muted)}
.sum b.hot{color:var(--accent)}
.sum b.bad{color:var(--red)}
.sum b.dim{color:var(--muted)}
@media (max-width:640px){
  .sum{grid-template-columns:repeat(2,1fr);gap:var(--s2)}
  .sum > div{padding:var(--s2) var(--s3)}
  .sum b{font-size:21px}
}

/* บนจอแคบแถวหนึ่งมีปุ่มสี่ตัว ถ้าใช้ขนาดปกติจะซ้อนกันสามชั้นจนแถวสูงเกินครึ่งจอ
   ปุ่มในกลุ่มนี้อยู่ติดกันเป็นก้อน ความเสี่ยงกดพลาดจึงน้อยกว่าปุ่มเดี่ยว */
@media (max-width:520px){
  .acts button{min-height:34px;padding:3px 9px;font-size:12.5px}
}

/* ตารางแอปมีสี่คอลัมน์ บนจอ 390px คอลัมน์ปุ่มเหลือราว 110px ปุ่มเลยซ้อนกันสามชั้น
   จนแถวเดียวสูง 170px — เห็นทีละสองแอป ที่แคบไม่ควรเอามาทำเป็นตารางตั้งแต่แรก
   จอแคบจึงคลี่เป็นบล็อก: ชื่อ เวอร์ชัน แล้วปุ่มเรียงเต็มความกว้าง */
@media (max-width:520px){
  /* สองคอลัมน์: ช่องติ๊กแคบ ๆ ซ้ายสุด ที่เหลือซ้อนกันลงมาในคอลัมน์ขวา
     เคยให้ทุกเซลล์เป็นบล็อกเต็มความกว้าง แล้วช่องติ๊กกินไปทั้งบรรทัดโดยเปล่าประโยชน์ */
  #rows tr{display:grid;grid-template-columns:26px minmax(0,1fr);gap:0 var(--s2);
    padding:10px 0;border-bottom:1px solid var(--line)}
  #rows tr:last-child{border-bottom:0}
  #rows td{display:block;border:0;padding:1px 0;grid-column:2;min-width:0}
  #rows td.chk{grid-column:1;grid-row:1;align-self:start;padding-top:5px;width:auto}
  /* #rows td มีน้ำหนักมากกว่า .hide-sm ต้องระบุซ้ำ ไม่งั้นคอลัมน์ที่ตั้งใจซ่อนจะโผล่ */
  #rows td.hide-sm{display:block}
  #rows td:last-child{padding-top:8px}
  #rows .acts{justify-content:flex-start}
  #rows td[colspan]{grid-column:1/-1;text-align:center;padding:var(--s5) 0}
  #rows .nm{font-size:15.5px}
  /* ป้าย 0/2 บอกครบอยู่แล้ว แถบยาวเต็มจอซ้ำของเดิมโดยไม่เพิ่มอะไร */
  #rows .bar{display:none}
  /* digest ไม่ได้ใช้ตัดสินใจอะไรบนมือถือ กินไปทั้งบรรทัดโดยไม่มีใครอ่าน */
  #rows .digest{display:none}
  /* หัวตารางไม่มีความหมายเมื่อแถวคลี่เป็นบล็อกแล้ว */
  #appTable thead{display:none}
}

/* =========================================================================
   เปลือกแบบแถบข้าง — ตามชอตอ้างอิง
   แถบข้างกว้างคงที่ เนื้อหาเลื่อนของมันเอง บนมือถือแถบนี้ลงไปอยู่ล่างจอ
   เพราะแถบข้างบนจอ 390px กินความกว้างไปเกือบครึ่ง
   ========================================================================= */
/* ตรึงแถบข้างแล้วเว้นที่ให้ด้วย padding — เคยทำ body เป็น grid แล้วพัง เพราะ dialog
   กับกล่องแจ้งเตือนเป็นลูกของ body เหมือนกัน มันเลยกลายเป็นช่องในตารางไปด้วย
   ดันเนื้อหาจริงตกไปแถวอื่น วิธีนี้ header/main ยังไหลตามปกติ sticky ก็ยังทำงาน */
body[data-page]{padding-left:230px;min-height:100dvh;
  transition:padding-left var(--fast)}
/* แบบย่อ — เหลือแต่ไอคอน ชื่อหน้าไปอยู่ใน title ให้ชี้แล้วเห็น
   จำกัดไว้เฉพาะจอกว้าง เพราะจอแคบแถบนี้เป็นแถบล่างอยู่แล้ว ไม่มีอะไรให้ย่อ
   ถ้าไม่จำกัด กฎพวกนี้จะไปบีบแถบล่างเหลือ 68px จนแท็บหายไปทั้งแถว */
@media (min-width:901px){
  :root[data-rail="mini"] body[data-page]{padding-left:68px}
  :root[data-rail="mini"] .rail{width:68px;padding-left:10px;padding-right:10px}
  :root[data-rail="mini"] .rbrand-t,
  :root[data-rail="mini"] .rme-t,
  :root[data-rail="mini"] .rme-c{display:none}
  :root[data-rail="mini"] .rtop{flex-direction:column;gap:var(--s2)}
  :root[data-rail="mini"] .ri{justify-content:center;padding:10px 0}
  :root[data-rail="mini"] .ri span{display:none}
  :root[data-rail="mini"] .rme{justify-content:center;padding:8px 0}
  /* เมนูกว้างกว่าแถบที่ย่อแล้ว ต้องกางออกด้านขวาแทนที่จะถูกบีบ */
  :root[data-rail="mini"] .pmenu{right:auto;width:232px}
}
.rail{
  position:fixed; left:0; top:0; bottom:0; width:230px; z-index:35;
  transition:width var(--fast);
  display:flex; flex-direction:column; gap:var(--s5);
  padding:var(--s5) var(--s3) var(--s4);
  background:var(--panel); border-right:1px solid var(--line);
  /* ห้ามตั้ง overflow ที่ตัวแถบ — มันจะกลายเป็นกรอบตัด แล้วเมนูโปรไฟล์ที่กางออกนอกแถบ
     จะโดนเฉือนหายไปครึ่งหนึ่ง ให้รายการเมนูข้างในเลื่อนเองแทน */
  overflow:visible;
}
.rbrand{display:flex;align-items:center;gap:10px;padding:0 var(--s2);text-decoration:none}
.rbrand:hover{text-decoration:none}
.rbrand-t{display:flex;flex-direction:column;min-width:0;line-height:1.3}
.rbrand-t b{font-size:15.5px;font-weight:700;letter-spacing:-.02em;color:var(--ink)}
.rbrand-t i{font-style:normal;font-size:11px;color:var(--muted)}

.rnav{display:flex;flex-direction:column;gap:3px;flex:1;
  overflow-y:auto;overflow-x:hidden;min-height:0}
.ri{
  display:flex;align-items:center;gap:11px;
  padding:10px var(--s3); border-radius:var(--r2);
  color:var(--muted); font-size:14px; font-weight:550; text-decoration:none;
  transition:background var(--fast), color var(--fast);
}
.ri:hover{background:var(--panel2);color:var(--ink);text-decoration:none}
.ri svg{width:19px;height:19px;flex:none}
/* รายการที่เปิดอยู่เป็นเม็ดสีเน้นทึบ เหมือนชอต — เห็นว่าอยู่หน้าไหนโดยไม่ต้องอ่าน */
.ri.on{background:var(--accent);color:var(--on-accent);box-shadow:0 3px 12px var(--accent-glow)}
.ri.on:hover{background:var(--accent);color:var(--on-accent)}

/* ---------- แผง "กำลังทำอยู่" ในเมนูซ้าย ----------
   รวมงานของทุกไซต์ไว้ที่เดียว เพราะเมนูอยู่ทุกหน้า — ต่างจากแถบบนของหน้าไซต์
   ที่เห็นได้แค่ไซต์ที่เปิดอยู่ แผงนี้จึงเป็นที่ที่ตอบได้ว่า "ตอนนี้ทำอะไรอยู่บ้าง"

   วางไว้เหนือปุ่มโปรไฟล์ ไม่ใช่ลอยทับเนื้อหา: ของที่ลอยต้องปิด และของที่ต้องปิด
   คือของที่คนปิดแล้วไม่เปิดอีก */
.rproc{flex:none;display:flex;flex-direction:column;gap:6px;
  padding-top:var(--s3);border-top:1px solid var(--line)}
/* หัวแผงเป็นปุ่มพับ — ถอดหน้าตาปุ่มมาตรฐานออกให้เหลือแค่หัวข้อที่กดได้ */
.rproc-h{display:flex;align-items:center;gap:6px;width:100%;
  padding:3px var(--s2);border:0;border-radius:var(--r1);background:transparent;
  box-shadow:none;min-height:0;text-align:left;cursor:pointer;
  font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  color:var(--muted)}
.rproc-h:hover{background:var(--panel2);color:var(--ink2);box-shadow:none}
.rproc-n{margin-left:auto;min-width:18px;padding:1px 6px;border-radius:999px;
  font-size:10.5px;font-weight:700;letter-spacing:0;text-align:center;
  color:var(--on-accent);background:var(--accent)}
/* ทิศลูกศรต้องตรงกับแผงพับอื่นในระบบ (.fold / .fold.on): พับ = ▼ กาง = ▲
   สลับทิศกันแค่ที่เดียวก็พอให้คนลังเลว่ากดแล้วจะเกิดอะไร */
.rproc-c{flex:none;display:grid;place-items:center;opacity:.7;
  transform:rotate(180deg);transition:transform var(--fast)}
.rproc-c svg{width:14px;height:14px}
.rproc.off .rproc-c{transform:rotate(0deg)}
/* พับแล้วเส้นคั่นกับหัวข้อยังอยู่ แต่ไม่ต้องเว้นที่ให้รายการที่ไม่มีแล้ว */
.rproc.off{padding-bottom:0}
/* เกินสามสี่ใบแล้วเลื่อนเอาในกล่องนี้ ไม่ใช่ดันปุ่มโปรไฟล์ตกจอ */
.rproc-l{display:flex;flex-direction:column;gap:2px;
  max-height:min(34vh,270px);overflow-y:auto;overflow-x:hidden}

.rp{display:flex;flex-direction:column;gap:4px;
  padding:7px var(--s2) 8px;border-radius:var(--r1);
  color:var(--ink2);text-decoration:none}
.rp:hover{background:var(--panel2);text-decoration:none}
.rp-n{display:flex;align-items:baseline;gap:6px;min-width:0;
  font-size:12px;font-weight:600;color:var(--ink)}
/* ชื่อยอมโดน … ได้ เปอร์เซ็นต์ห้ามหาย — ต้องห่อชื่อเป็นกล่องของตัวเอง
   ไม่งั้นข้อความเปล่า ๆ ใน flex จะดันตัวเลขทะลุขอบแถบไปแทนที่จะหดตัวเอง */
.rp-n>span{min-width:0;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rp-n b{flex:none;font-size:11px;font-weight:700;
  font-variant-numeric:tabular-nums;color:var(--accent)}
.rp-s{font-size:10.5px;color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* แถบลายทางแบบเดียวกับตัวบอกงานของ Jenkins — ลายที่เลื่อนบอกว่ายังเดินอยู่
   แม้ตัวเลขจะค้าง (image ที่มี layer ใหญ่ไม่กี่ก้อนค้างเลขเดิมได้เป็นสิบนาที) */
.rp-b{display:block;height:6px;border-radius:999px;overflow:hidden;
  background:color-mix(in srgb,var(--ink) 10%,transparent)}
.rp-b>i{display:block;height:100%;border-radius:999px;
  background-color:var(--accent);
  background-image:repeating-linear-gradient(115deg,
    color-mix(in srgb,#fff 42%,transparent) 0 7px, transparent 7px 14px);
  background-size:30.9px 100%;
  animation:rpflow .8s linear infinite;
  transition:width .45s ease}
@keyframes rpflow{to{background-position:30.9px 0}}
/* ไม่รู้ความคืบหน้า = ลายเต็มแถบแต่จางลง ไม่ใช่แถบว่างที่ดูเหมือนค้าง */
.rp.idle .rp-b>i{width:100%;opacity:.45}
@media (prefers-reduced-motion:reduce){
  .rp-b>i{animation:none}
  .rp.idle .rp-b>i{opacity:.3}}

/* แถบย่อเหลือแต่ไอคอน / จอแคบที่แถบไปอยู่ล่างจอ — ไม่มีที่ให้แผงนี้อยู่
   เวอร์ชันมือถือของแผงนี้ยังไม่ได้ออกแบบ ซ่อนดีกว่าบีบจนอ่านไม่ออก */
@media (max-width:900px){.rproc{display:none}}
:root[data-rail="mini"] .rproc{display:none}

/* ---------- หัวแถบ + ปุ่มย่อ ---------- */
.rtop{display:flex;align-items:center;gap:var(--s2)}
.rtog{
  flex:none;min-height:28px;width:28px;padding:0;border-radius:var(--r1);
  display:grid;place-items:center;
  background:transparent;border:1px solid transparent;box-shadow:none;color:var(--muted);
}
.rtog svg{width:16px;height:16px}
.rtog:hover{background:var(--panel2);border-color:var(--line);color:var(--ink);box-shadow:none}

/* ---------- ปุ่มโปรไฟล์ + เมนูของมัน ---------- */
.rfoot{position:relative;display:flex;flex-direction:column;gap:var(--s2)}
.rme{
  display:flex;align-items:center;gap:9px;width:100%;
  padding:8px var(--s2);border-radius:var(--r2);
  background:var(--panel2);border:1px solid var(--line);box-shadow:none;text-align:left;
}
.rme:hover{background:var(--panel3);border-color:var(--line2);box-shadow:none}
.rme[aria-expanded="true"]{border-color:var(--accent-line);background:var(--accent-soft)}
.av{width:30px;height:30px;flex:none;border-radius:999px;display:grid;place-items:center;
  font-size:13px;font-weight:700;color:var(--on-accent);
  background:linear-gradient(145deg,var(--accent2),var(--accent))}
.rme-t{display:flex;flex-direction:column;min-width:0;flex:1;line-height:1.3}
.rme-t b{font-size:12.5px;font-weight:600;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rme-t i{font-style:normal;font-size:11px;color:var(--muted)}
.rme-c{flex:none;color:var(--muted);display:grid;place-items:center;
  transition:transform var(--fast)}
.rme-c svg{width:15px;height:15px}
.rme[aria-expanded="true"] .rme-c{transform:rotate(180deg)}

.pmenu{
  position:absolute; left:0; right:0; bottom:calc(100% + 6px); z-index:45;
  padding:var(--s3); border-radius:var(--r3);
  background:var(--panel); border:1px solid var(--line); box-shadow:var(--sh3);
  animation:pop .16s cubic-bezier(.2,.9,.3,1.2);
}
.pm-h{padding:0 var(--s1) var(--s3);border-bottom:1px solid var(--line);
  margin-bottom:var(--s3);line-height:1.35}
.pm-h b{display:block;font-size:12.5px;font-weight:650;overflow-wrap:anywhere}
.pm-h i{font-style:normal;font-size:11px;color:var(--muted)}
.pm-s{font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);
  font-weight:700;margin:0 0 6px var(--s1)}
.pm-out{
  width:100%;margin-top:var(--s3);padding-top:var(--s3);
  border:0;border-top:1px solid var(--line);border-radius:0;background:transparent;
  box-shadow:none;color:var(--red);display:flex;align-items:center;gap:9px;
  justify-content:flex-start;font-weight:550;
}
.pm-out:hover{background:transparent;color:var(--red);box-shadow:none;
  border-top-color:var(--line)}
.pm-out svg{width:16px;height:16px;flex:none}

/* ปุ่มธีมในเมนูเรียงลงมาพร้อมคำอธิบาย ต่างจากตอนอยู่ในแถบที่มีแต่ไอคอน */
.seg{display:flex;flex-direction:column;gap:2px;padding:3px;border-radius:var(--r2);
  background:var(--panel2);border:1px solid var(--line);margin-bottom:var(--s3)}
.seg button{
  min-height:32px;padding:4px 9px;border:0;background:transparent;box-shadow:none;
  color:var(--ink2);border-radius:calc(var(--r2) - 3px);
  display:flex;align-items:center;gap:9px;font-size:13px;font-weight:550;
}
.seg button svg{width:16px;height:16px;flex:none}
.seg button:hover:not(.on){background:var(--panel3);color:var(--ink);box-shadow:none}
.seg button.on{background:var(--accent);color:var(--on-accent);box-shadow:var(--sh1)}

/* ---------- แถบทักทาย ---------- */
.hero{
  position:relative; overflow:hidden;
  border:1px solid var(--line); border-radius:var(--r4);
  padding:var(--s5) var(--s5) var(--s4);
  margin-bottom:var(--s4); box-shadow:var(--sh1);
  background:
    radial-gradient(660px 300px at 8% -30%, var(--accent-soft), transparent 68%),
    var(--panel);
}
.hero .hi{font-size:13.5px;color:var(--muted);margin:0}
.hero h1{margin:2px 0 0;font-size:clamp(21px,3vw,27px);font-weight:700;letter-spacing:-.03em}
.hero .chips{display:flex;gap:var(--s2);flex-wrap:wrap;margin-top:var(--s4)}
/* ชิปตัวเลขใต้ชื่อห้องในชอต — ไอคอน/ตัวเลข/หน่วย อยู่ในเม็ดเดียว */
.chip{
  display:inline-flex;align-items:center;gap:7px;
  padding:7px 13px;border-radius:999px;
  background:var(--panel2);border:1px solid var(--line);
  font-size:13px;color:var(--ink2);
}
.chip b{font-weight:700;font-variant-numeric:tabular-nums}
.chip.hot b{color:var(--accent)}
.chip.bad b{color:var(--red)}
.chip .dot{width:7px;height:7px;border-radius:999px;background:currentColor;flex:none}
.chip.ok{color:var(--green);background:var(--green-soft);border-color:var(--green-line)}

/* ---------- คอลัมน์ขวาแบบชอต ---------- */
.split{display:grid;grid-template-columns:minmax(0,1.9fr) minmax(280px,.9fr);
  gap:var(--s4);align-items:start}
@media (max-width:1080px){.split{grid-template-columns:minmax(0,1fr)}}

/* ---------- เกจวงแหวน ---------- */
/* conic-gradient ทำวงแหวนได้โดยไม่ต้องมี svg หรือไลบรารีกราฟ */
/* วงในทับเอาแทนที่จะใช้ mask — mask ยังมีเบราว์เซอร์ที่ทำไม่เหมือนกัน แล้วจะได้
   วงกลมทึบแทนวงแหวนโดยไม่มีอะไรฟ้อง */
.ring{position:relative;width:152px;height:152px;margin:var(--s2) auto var(--s4);
  border-radius:999px;
  background:conic-gradient(from -90deg,
             var(--accent2) 0, var(--accent) calc(var(--pct,0) * 1%),
             var(--panel2) 0);
}
.ring::after{content:"";position:absolute;inset:14px;border-radius:999px;
  background:var(--panel);box-shadow:inset 0 1px 6px rgba(0,0,0,.12)}
.ring-wrap{position:relative;display:grid;place-items:center}
.ring-val{position:absolute;text-align:center;line-height:1.15;z-index:1;
  margin-bottom:var(--s2)}
.ring-val b{display:block;font-size:30px;font-weight:700;letter-spacing:-.03em;
  font-variant-numeric:tabular-nums}
.ring-val span{font-size:11.5px;color:var(--muted)}

/* ---------- แถบสัดส่วนเล็ก ๆ ในการ์ดขวา ---------- */
.mini{display:flex;flex-direction:column;gap:9px}
.mini-row{display:grid;grid-template-columns:1fr auto;gap:var(--s2) var(--s3);
  align-items:center;font-size:12.5px}
.mini-row .t{color:var(--ink2);font-weight:600;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.mini-row .v{color:var(--muted);font-variant-numeric:tabular-nums}
.mini-row .track{grid-column:1/-1;height:6px;border-radius:999px;background:var(--panel2);
  overflow:hidden;border:1px solid var(--line)}
.mini-row .track i{display:block;height:100%;border-radius:999px;
  background:linear-gradient(90deg,var(--accent2),var(--accent))}
.mini-row .track i.bad{background:linear-gradient(90deg,var(--red),var(--amber))}

/* ---------- เม็ดข้อมูลเล็กในการ์ด (แบบ Front Door / Windows / Cameras) ---------- */
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(88px,1fr));gap:var(--s2)}
.tile{background:var(--panel2);border:1px solid var(--line);border-radius:var(--r2);
  padding:10px var(--s3);line-height:1.35}
.tile b{display:block;font-size:17px;font-weight:700;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.tile span{font-size:11px;color:var(--muted)}
.tile.hot b{color:var(--accent)}
.tile.bad b{color:var(--red)}

/* ---------- แถวอุปกรณ์แบบชอต ---------- */
/* ไอคอนในกรอบมนหน้าชื่อ ทำให้กวาดตาหาแถวได้เร็วกว่าตัวหนังสือล้วน */
.ico{width:32px;height:32px;flex:none;border-radius:var(--r1);display:grid;place-items:center;
  background:var(--accent-soft);color:var(--accent);font-size:12px;font-weight:800}
.cell-app{display:flex;align-items:center;gap:11px}
.cell-app .t{min-width:0}
.cell-app .t b{display:block;font-weight:650;letter-spacing:-.01em}
.cell-app .t span{font-size:11.5px;color:var(--muted)}

/* ---------- มือถือ: แถบข้างลงไปอยู่ล่างจอ ---------- */
@media (max-width:900px){
  body[data-page]{padding-left:0}
  .rail{
    position:fixed;left:0;right:0;bottom:0;top:auto;height:auto;width:100%;
    flex-direction:row;align-items:center;gap:var(--s2);z-index:40;
    padding:8px var(--s3);padding-bottom:max(8px, env(safe-area-inset-bottom));
    border-right:0;border-top:1px solid var(--line);box-shadow:0 -6px 20px rgba(0,0,0,.10);
  }
  .rtop{display:none}
  .rnav{flex-direction:row;gap:4px;flex:1}
  .ri{flex:1;flex-direction:column;gap:3px;padding:6px 4px;font-size:10.5px;
    border-radius:var(--r1);text-align:center}
  .ri span{white-space:nowrap}
  .rnav > span[hidden]{display:none}
  .rnav > span{flex:1;display:flex}
  /* ธีมกับสีย้ายเข้าเมนูโปรไฟล์แล้ว แถบล่างจึงเหลือแค่แท็บกับปุ่มโปรไฟล์ */
  .rfoot{flex:none}
  .rme{padding:5px;gap:0;background:transparent;border:0;width:auto}
  .rme:hover,.rme[aria-expanded="true"]{background:transparent;border:0}
  .rme-t,.rme-c{display:none}
  /* เมนูกางขึ้นจากแถบล่าง ชิดขวาและกว้างพอให้อ่านอีเมลได้ */
  .pmenu{right:0;left:auto;width:min(268px, calc(100vw - 24px));
    bottom:calc(100% + 10px)}
  /* กันเนื้อหาท้ายหน้าถูกแถบล่างทับ */
  body[data-page] > main{padding-bottom:104px}
}

/* ปุ่มย้อนกลับในแถบหัวของหน้าไซต์ — วงกลมเล็กแทนคำว่า "กลับ" ที่กินที่ */
.back{
  width:32px;height:32px;flex:none;border-radius:var(--r1);
  display:grid;place-items:center;text-decoration:none;
  background:var(--panel2);border:1px solid var(--line);color:var(--ink2);
  font-size:16px;line-height:1;
  transition:background var(--fast), border-color var(--fast), color var(--fast);
}
.back:hover{background:var(--accent-soft);border-color:var(--accent-line);
  color:var(--accent);text-decoration:none}

/* แถวที่ pod ไม่ครบ ให้กรอบไอคอนเปลี่ยนสีด้วย จะได้เห็นตั้งแต่ยังไม่อ่านตัวเลข */
.ico.bad{background:var(--red-soft);color:var(--red)}
.cell-app .t b{display:inline}
.cell-app .t > span{display:block;font-size:11.5px;color:var(--muted)}

/* =========================================================================
   จานสีเน้นที่ผู้ใช้เลือกได้
   แต่ละจานมี 12 ค่า: หกค่าของโหมดสว่าง (-l) และหกของโหมดมืด (-d)
   ตรรกะสว่าง/มืดอยู่ข้างบนที่เดียว ที่นี่จึงมีแต่ค่าสี ไม่ต้องเขียนซ้ำตามโหมด

   oa = สีตัวอักษรบนพื้นสีเน้น โหมดสว่างพื้นเข้มจึงใช้ขาว โหมดมืดพื้นอ่อนจึงใช้เข้ม
   ถ้าใช้ขาวทั้งคู่ โหมดมืดจะเหลือคอนทราสต์ราว 1.9:1 ซึ่งอ่านไม่ออก
   ========================================================================= */
:root, :root[data-accent="iris"]{
  --a-l:#4b3fce; --a2-l:#6155e8; --as-l:#ecebfd; --al-l:#c3bef9;
  --ag-l:rgba(97,85,232,.26); --oa-l:#ffffff;
  --a-d:#a89fff; --a2-d:#bdb6ff; --as-d:#241f52; --al-d:#433a80;
  --ag-d:rgba(168,159,255,.22); --oa-d:#120b33;
}
:root[data-accent="jade"]{
  --a-l:#0b6b62; --a2-l:#0d8175; --as-l:#dcf2ee; --al-l:#a3ddd3;
  --ag-l:rgba(13,129,117,.26); --oa-l:#ffffff;
  --a-d:#54cdb9; --a2-d:#76dece; --as-d:#0c3330; --al-d:#1a5750;
  --ag-d:rgba(84,205,185,.22); --oa-d:#03231f;
}
:root[data-accent="copper"]{
  --a-l:#8a4f28; --a2-l:#a35f30; --as-l:#f8ebe0; --al-l:#e2c0a3;
  --ag-l:rgba(163,95,48,.26); --oa-l:#ffffff;
  --a-d:#e0a173; --a2-d:#edb890; --as-d:#37241a; --al-d:#5e4230;
  --ag-d:rgba(224,161,115,.22); --oa-d:#2a1508;
}
:root[data-accent="plum"]{
  --a-l:#82306a; --a2-l:#9b3a7f; --as-l:#f9e6f3; --al-l:#eeb4dc;
  --ag-l:rgba(155,58,127,.26); --oa-l:#ffffff;
  --a-d:#e29ccd; --a2-d:#efb6dd; --as-d:#3a1631; --al-d:#642a55;
  --ag-d:rgba(226,156,205,.22); --oa-d:#2c0a23;
}
:root[data-accent="ocean"]{
  --a-l:#1a5e93; --a2-l:#1f71ae; --as-l:#e3eff9; --al-l:#aacee9;
  --ag-l:rgba(31,113,174,.26); --oa-l:#ffffff;
  --a-d:#79bdea; --a2-d:#98cff3; --as-d:#122d44; --al-d:#254d6f;
  --ag-d:rgba(121,189,234,.22); --oa-d:#04192b;
}
:root[data-accent="graphite"]{
  --a-l:#3f4a5c; --a2-l:#4e5b70; --as-l:#eceff4; --al-l:#c2cad6;
  --ag-l:rgba(78,91,112,.26); --oa-l:#ffffff;
  --a-d:#adbacd; --a2-d:#c4cfde; --as-d:#232b37; --al-d:#3b4657;
  --ag-d:rgba(173,186,205,.22); --oa-d:#101720;
}

/* ---------- แถวเลือกสี ---------- */
.sw{display:grid;grid-template-columns:repeat(6,1fr);gap:6px}
.sw button{
  min-height:28px;padding:0;border-radius:var(--r1);
  border:2px solid transparent;background:var(--sw);box-shadow:none;
}
.sw button:hover:not(.on){box-shadow:none;border-color:var(--line2);transform:none}
/* วงที่เลือกอยู่ใช้ขอบสองชั้น จะได้เห็นชัดบนทุกสีโดยไม่ต้องใส่เครื่องหมายถูกทับสี */
.sw button.on{border-color:var(--panel);box-shadow:0 0 0 2px var(--ink)}
.sw button:focus-visible{outline-offset:3px}


/* ---------- แผงที่พับไว้ ---------- */
/* รายการพวกนี้ส่วนใหญ่ว่าง ถ้ากางไว้ตลอดจะกินครึ่งจอโดยไม่มีอะไรให้ดู
   หัวแผงบอกจำนวนไว้ กดแล้วค่อยกาง */
.fold{padding:0;overflow:hidden}
.fold-h{
  display:flex;align-items:center;gap:var(--s3);width:100%;
  padding:var(--s3) var(--s4);border:0;border-radius:var(--r3);
  background:transparent;box-shadow:none;text-align:left;
}
.fold-h:hover{background:var(--panel3);box-shadow:none;border:0}
.fold.on .fold-h{border-radius:var(--r3) var(--r3) 0 0;border-bottom:1px solid var(--line)}
.fold-t{font-size:13px;font-weight:650;letter-spacing:-.01em;color:var(--ink)}
.fold-n{margin-left:auto;display:flex;align-items:center;gap:var(--s2);
  flex-wrap:wrap;justify-content:flex-end;min-width:0}
/* ชื่อกิ่งยอมหดได้ ป้ายตัวเลขห้ามโดนตัด — ตัวเลขคือเหตุผลที่คนกวาดตาดูแถวนี้ */
.fold-h .fold-t{min-width:0;overflow:hidden;text-overflow:ellipsis}
.fold-n .pill{white-space:nowrap}
.fold-c{color:var(--muted);display:grid;place-items:center;transition:transform var(--fast)}
.fold-c svg{width:16px;height:16px}
.fold.on .fold-c{transform:rotate(180deg)}
.fold-b{padding:var(--s3) var(--s4) var(--s4)}
.fold-b .toolbar{margin-bottom:var(--s2)}

/* ---------- เลือกหลายรายการ ---------- */
th.chk,td.chk{width:34px;padding-right:0}
td.chk input,th.chk input{cursor:pointer}
tr.picked{background:var(--accent-soft)}
tr.picked:hover{background:var(--accent-soft)}
/* แถบคำสั่งลอยอยู่ล่างจอ เห็นได้ตลอดแม้เลื่อนตารางไปไกล */
.bulk{
  position:sticky;bottom:var(--s3);z-index:20;
  display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;
  margin:var(--s3) 0 0;padding:10px var(--s4);
  border-radius:var(--r3);background:var(--panel);
  border:1px solid var(--accent-line);box-shadow:var(--sh3);
  animation:rise .18s cubic-bezier(.2,.9,.3,1.1);
}
.bulk b{font-variant-numeric:tabular-nums}
.bulk .sp{flex:1}
@media (max-width:640px){
  .bulk{padding:var(--s2) var(--s3);gap:6px}
  .bulk .sp{display:none}
  .bulk button{flex:1}
}

/* ---------- ป้ายยาว/ป้ายสั้น ---------- */
/* จอแคบใช้คำสั้นหรือไอคอนล้วน แต่ยังต้องมีคำเต็มไว้ให้เครื่องอ่านหน้าจอและ title
   จึงเขียนทั้งสองแบบไว้แล้วสลับด้วย css ไม่ใช่ให้จาวาสคริปต์เดาขนาดจอ
   (เดาแล้วต้องมาคอยฟัง resize ซึ่งพลาดง่ายกว่า) */
.only-sm{display:none}
@media (max-width:640px){
  .only-lg{display:none}
  .only-sm{display:inline}
}

/* แถบคำสั่งบนจอแคบ — ปุ่มแบ่งความกว้างเท่ากัน ไม่ตัดคำกลางปุ่ม */
@media (max-width:900px){
  /* แถบเมนูล่างตรึงอยู่ ถ้าแถบคำสั่งใช้ sticky ที่ก้นหน้าจอ มันจะไปอยู่ "ใต้" เมนู
     คือเลือกของแล้วไม่เห็นปุ่มสั่งเลย ต้องตรึงไว้เหนือเมนูเป็นชั้นของตัวเอง */
  .bulk{
    position:fixed; left:var(--s3); right:var(--s3); margin:0;
    bottom:calc(76px + env(safe-area-inset-bottom));
    z-index:38;
  }
}
@media (max-width:640px){
  .bulk{gap:6px;padding:var(--s2) var(--s3);align-items:stretch}
  .bulk > b, .bulk > span{align-self:center}
  /* ปล่อยให้ปุ่มกว้างตามข้อความ — เคยบังคับให้เท่ากันทุกปุ่ม แล้วปุ่มที่ข้อความยาวสุด
     ถูกบีบจนตัดคำกลางปุ่ม ("↑ deplo") ซึ่งอ่านแล้วไม่รู้ว่าปุ่มอะไร */
  .bulk button{flex:0 1 auto;white-space:nowrap;padding:6px 9px}
  .bulk{overflow-x:auto}
}

/* ปุ่มที่มีแต่ไอคอน — ให้ svg อยู่กลางและขนาดคงที่ ไม่ขึ้นกับฟอนต์ emoji ของเครื่อง */
/* ห้ามตั้ง display ให้ .only-lg/.only-sm ที่นี่ — ตัวเลือกจะจำเพาะกว่ากฎกลาง
   แล้วทั้งคำเต็มและคำสั้นจะแสดงพร้อมกัน ปุ่มไอคอนเลยมีไอคอนซ้อนกันสองอัน */
.ico-btn{display:inline-flex;align-items:center;justify-content:center;
  padding-left:9px;padding-right:9px}
.ico-btn svg{width:16px;height:16px;display:block}
@media (max-width:640px){
  .acts{gap:5px}
}

/* ---------- เฟืองบนการ์ดไซต์ ---------- */
/* วางทับมุมขวาบนของการ์ดที่ตัวมันเองเป็นปุ่ม — จึงต้องเป็น element แยกที่กิน event เอง
   ไม่ใช่ปุ่มซ้อนปุ่ม ซึ่ง html ไม่ให้ทำและเบราว์เซอร์จะจัดวางเพี้ยน */
.gear{
  position:absolute; top:var(--s3); right:var(--s3); z-index:2;
  width:30px; height:30px; border-radius:var(--r1);
  display:grid; place-items:center; cursor:pointer;
  color:var(--muted); background:var(--panel2); border:1px solid var(--line);
  transition:color var(--fast), border-color var(--fast), background var(--fast);
}
.gear svg{width:16px;height:16px}
.gear:hover{color:var(--accent);border-color:var(--accent-line);background:var(--accent-soft)}
.gear:focus-visible{outline:2px solid var(--accent2);outline-offset:2px}
/* ชื่อไซต์ต้องไม่ไหลไปใต้เฟือง */
.site .cell-app{padding-right:34px}

/* ---------- ตารางค่าตั้ง ---------- */
.set-row{display:grid;grid-template-columns:minmax(0,1fr);gap:4px;
  padding:var(--s3) 0;border-bottom:1px solid var(--line)}
.set-row:last-child{border-bottom:0}
.set-row .k{font-family:var(--mono);font-size:12.5px;font-weight:650}
.set-row .n{font-size:12px;color:var(--muted)}
.set-row input{width:100%}
.set-row .st{font-size:11.5px}

/* ---------- แถวที่ติ๊กเลือกได้ (รายชื่อคนตอนมอบสิทธิ์) ---------- */
.set-row.pickable{display:flex;align-items:center;gap:var(--s3);cursor:pointer;
  padding:7px var(--s2);border-radius:var(--r1)}
.set-row.pickable:hover{background:var(--panel2)}
.set-row.pickable .k{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}
/* กฎ .set-row input{width:100%} มีไว้สำหรับช่องพิมพ์ในกล่องตั้งค่า พอเอาแถวมาใช้กับ
   ช่องติ๊ก มันเลยยืดช่องติ๊กเต็มบรรทัดจนข้อความถูกบีบเหลือศูนย์ (เจอจริงจากหน้าจอ) */
/* รายการที่ติ๊กเลือก — มีเส้นคั่นบาง ๆ ให้แต่ละแถวอ่านแยกกันออก และสูงพอให้กดโดน */
.scroll.list{max-height:46vh;border:1px solid var(--line);border-radius:var(--r2);
  padding:var(--s2)}
.scroll.list .set-row + .set-row{border-top:1px solid var(--line)}
.set-row.pickable input[type="checkbox"],
.set-row.pickable input[type="radio"]{flex:0 0 auto;width:16px;height:16px;margin:0}

/* ---------- การ์ดของหน้าดีพลอย ----------
   เลขเวอร์ชันคือสิ่งที่คนมาหา ต้องอ่านได้จากระยะไกลและบอกสถานะด้วยสีในตัวมันเอง */
.site.dep{align-items:stretch}
.vrow{display:flex;align-items:baseline;gap:var(--s2);margin:var(--s3) 0 var(--s2);
  flex-wrap:wrap}
.vnow{font-size:20px;font-weight:700;letter-spacing:-0.4px}
.vnow.ok{color:var(--green)}
.vnow.bad{color:var(--red)}
.vnow.flat{color:var(--muted)}
.varrow{color:var(--muted)}
.vwant{font-size:17px;font-weight:650;color:var(--accent)}
.vpickrow{margin:var(--s2) 0 0}
.vpickrow .vpick{flex:1;min-width:0}
/* งานที่กำลังวิ่งอยู่ ต้องสะดุดตาจากการ์ดที่อยู่เฉย ๆ และที่พังต้องสะดุดตากว่า */
.site.dep.live{border-color:var(--accent2);box-shadow:0 0 0 3px var(--accent-glow)}
.site.dep.bad{border-color:var(--red-line);box-shadow:0 0 0 3px var(--red-soft)}
/* ทำ image ไว้แล้วรอคนมีสิทธิ์กดส่งขึ้นไซต์ — คนละเรื่องกับล้ม ต้องไม่ใช้สีเดียวกัน */
.site.dep.ready{border-color:var(--amber-line);box-shadow:0 0 0 3px var(--amber-soft)}
.runmsg.ready{color:var(--amber);font-weight:600}
/* ปุ่ม public เป็นไอคอน — จอกว้างมีคำกำกับด้วย จอแคบเหลือแต่ไอคอน (มี title/aria) */
#pbGo{gap:6px}
#pbGo svg{width:16px;height:16px}
/* ป้ายขั้นตอน: บอกสถานะด้วยสีอย่างเดียว ไม่มี emoji — สีเทาคือยังไม่ถึง */
.step.skip{opacity:.6}
.step.wait{opacity:.55}
/* ตั้งเวอร์ชันไว้แล้วแต่ไซต์ยังไม่ได้ของ — เรืองค้างไว้จนกว่าจะตรงกัน ไม่ใช่แค่ป้าย
   เล็ก ๆ ที่กวาดตาผ่านได้ (การ์ดเรียงกันเป็นสิบใบ ใบที่ยังค้างต้องหาเจอจากระยะไกล)
   สถานะ live/bad/ready ของงานที่กำลังวิ่งสำคัญกว่า จึงให้ทับอันนี้ได้ */
.site.dep.waiting{border-color:var(--amber-line);
  animation:wait-glow 2.4s ease-in-out infinite}
@keyframes wait-glow{
  0%,100%{box-shadow:0 0 0 2px var(--amber-soft)}
  50%{box-shadow:0 0 0 5px var(--amber-soft)}
}
/* ปิดภาพเคลื่อนไหวแล้วยังต้องเห็นว่าใบไหนค้าง — กฎรวมของหน้าหยุดแค่การกะพริบ
   ส่วนขอบกับเงายังอยู่ */
@media (prefers-reduced-motion:reduce){
  .site.dep.waiting{box-shadow:0 0 0 3px var(--amber-soft)}
}
/* ทั้งใบกดได้ — ต้องรู้สึกได้ว่ากดได้ ไม่ใช่ต้องลองกดดู */
.site.dep{cursor:pointer}
.site.dep:hover{border-color:var(--line2)}
/* กล่อง commit ของเวอร์ชัน — ย่อเป็นบรรทัดเดียวไว้ก่อน ชี้เมาส์แล้วค่อย ๆ กาง
   เนื้อเต็มออกมา ถ้าโชว์เต็มตลอดเวลา การ์ดในกริดจะสูงไม่เท่ากันจนกวาดตาหายาก */
.cmt{margin-top:6px;padding:6px 8px;font-size:12px;color:var(--ink);
  border:1px solid var(--line); border-radius:var(--r2); background:var(--panel2);
  transition:border-color .15s ease, background .15s ease}
.cmt .cmt-1{display:flex;align-items:baseline;gap:6px;min-width:0}
.cmt .sha{color:var(--accent);flex:0 0 auto}
/* หัวข้อยาวแค่ไหนก็บรรทัดเดียว ส่วนเวลาเกาะขวาไม่ให้ถูกดันหาย */
.cmt .subj{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto}
.cmt .when{flex:0 0 auto;font-size:11.5px}
/* ย่อ/กางด้วย grid 0fr→1fr เพื่อให้สูงตามเนื้อจริงโดยไม่ต้องเดาความสูงสูงสุด
   ลูกต้องมีชิ้นเดียว (ดู commitLine) ไม่งั้น text node ที่คั่นจะกลายเป็นแถวเพิ่ม */
.cmt .cmt-2{display:grid;grid-template-rows:0fr;opacity:0;
  transition:grid-template-rows .22s ease, opacity .18s ease}
.cmt .cmt-2 > .cmt-in{overflow:hidden;min-height:0;display:block}
.cmt.has-more:hover,.cmt.has-more:focus-within{border-color:var(--accent2);
  background:var(--panel)}
.cmt.has-more:hover .cmt-2,.cmt.has-more:focus-within .cmt-2{
  grid-template-rows:1fr;opacity:1}
.cmt .who{display:block;font-size:11.5px;margin-top:6px}
/* เนื้อ commit อยู่ในกรอบของตัวเอง แบบเดียวกับที่หน้า git แสดง — อ่านง่ายกว่า
   ข้อความลอย ๆ ต่อท้ายชื่อคนแก้ */
.cmt .cmt-body{display:block;margin-top:6px;padding:6px 8px;white-space:pre-wrap;
  font-family:var(--mono);font-size:11.5px;color:var(--ink);
  border:1px solid var(--line);border-radius:var(--r2);background:var(--bg)}
/* กล่องของเวอร์ชันที่กำลังจะไป — มีเฉพาะตอนที่ยังไม่ตรงกับที่ตั้งไว้
   ตอนจะปล่อยของ คนอยากรู้ว่า "ของใหม่คืออะไร" มากกว่าของที่รันอยู่ */
.cmt.next{border-style:dashed}
.cmt.next .cmt-1::before{content:"→";color:var(--muted);flex:0 0 auto}
.runmsg{font-size:12.5px;color:var(--muted);margin-top:6px}
.runmsg.fail,.runmsg.stopped{color:var(--red);font-weight:600}
.runmsg.ok{color:var(--green)}
.steps{display:flex;flex-wrap:wrap;gap:4px;margin-top:var(--s2)}
.step{font-size:11.5px;padding:2px 7px;border-radius:999px;border:1px solid var(--line);
  color:var(--muted);background:var(--panel2)}
.step.run{border-color:var(--accent2);color:var(--accent)}
.step.ok{border-color:var(--green-line);color:var(--green)}
.step.fail{border-color:var(--red-line);color:var(--red)}
.step.warn{border-color:var(--amber-line);color:var(--amber)}

/* ---------- สวิตช์มุมมอง ควบคุม/ดีพลอย ----------
   ใหญ่กว่าแท็บ namespace ตั้งใจ — สองอันนี้เปลี่ยนทั้งหน้า ไม่ใช่กรองรายการ
   ถ้าหน้าตาเหมือนกันคนจะไม่ทันสังเกตว่าตัวเองอยู่มุมมองไหนแล้วกดผิด */
.tabs.viewsw{margin:0 0 var(--s4)}
.tabs.viewsw .tab{font-weight:650;padding:8px 18px}
.tabs.viewsw .tab.on{background:var(--accent-soft);color:var(--accent);
  border-color:var(--accent2)}

/* ---------- การ์ด "สร้างใหม่" ----------
   อยู่ท้ายแถวเดียวกับของที่มีอยู่ เพื่อให้สร้างตรงชั้นที่ยืนอยู่ ไม่ต้องไปพิมพ์ path เอง */
.site.new{border-style:dashed;background:transparent;color:var(--muted)}
.site.new:hover{border-style:solid;color:var(--ink);background:var(--panel)}
.site.new .ico.plus{background:transparent;border:1px dashed var(--line2);
  color:var(--muted);font-size:20px;font-weight:400}
.head-row{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;
  margin-bottom:var(--s3)}
.head-row h2{margin:0}

/* ---------- ป้ายกำกับของไซต์ ----------
   สีมาจากชุดนี้เท่านั้น ไม่ให้พิมพ์ค่าสีเอง เพราะสีที่เลือกมาลอย ๆ จะอ่านไม่ออก
   ในโหมดใดโหมดหนึ่งเสมอ ชุดนี้จับคู่ไว้แล้วทั้งสว่างและมืด */
.tag{display:inline-flex;align-items:center;gap:4px;font-size:11.5px;line-height:1;
  padding:3px 8px;border-radius:999px;border:1px solid var(--tg-line);
  background:var(--tg-soft);color:var(--tg-ink);white-space:nowrap}
.tag.slate {--tg-ink:#44546a;--tg-soft:#eef1f5;--tg-line:#d3dbe5}
.tag.blue  {--tg-ink:#1f5b9e;--tg-soft:#e3eefb;--tg-line:#b9d4f0}
.tag.teal  {--tg-ink:#0f6b6b;--tg-soft:#ddf1f0;--tg-line:#a9dbd8}
.tag.green {--tg-ink:#0f7047;--tg-soft:#d8f0e4;--tg-line:#a3d7bf}
.tag.amber {--tg-ink:#805c0a;--tg-soft:#f8ecd0;--tg-line:#e2c88a}
.tag.red   {--tg-ink:#9a4128;--tg-soft:#f8e3da;--tg-line:#e4b7a5}
.tag.purple{--tg-ink:#5b3fa0;--tg-soft:#ebe5f9;--tg-line:#cbbcee}
.tag.pink  {--tg-ink:#9c3468;--tg-soft:#fae0ec;--tg-line:#efb6d2}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .tag.slate {--tg-ink:#a8b6c6;--tg-soft:#1b242e;--tg-line:#2f3d4c}
  :root:not([data-theme="light"]) .tag.blue  {--tg-ink:#7fb3ee;--tg-soft:#14212f;--tg-line:#254058}
  :root:not([data-theme="light"]) .tag.teal  {--tg-ink:#6fcac5;--tg-soft:#112726;--tg-line:#1f4643}
  :root:not([data-theme="light"]) .tag.green {--tg-ink:#52b98a;--tg-soft:#0e2a20;--tg-line:#1d4c39}
  :root:not([data-theme="light"]) .tag.amber {--tg-ink:#dcb160;--tg-soft:#2d2415;--tg-line:#524125}
  :root:not([data-theme="light"]) .tag.red   {--tg-ink:#dd8b6b;--tg-soft:#33201a;--tg-line:#5c392c}
  :root:not([data-theme="light"]) .tag.purple{--tg-ink:#b49ae8;--tg-soft:#211c33;--tg-line:#3b3357}
  :root:not([data-theme="light"]) .tag.pink  {--tg-ink:#e493bb;--tg-soft:#2f1a26;--tg-line:#523043}
}
[data-theme="dark"] .tag.slate {--tg-ink:#a8b6c6;--tg-soft:#1b242e;--tg-line:#2f3d4c}
[data-theme="dark"] .tag.blue  {--tg-ink:#7fb3ee;--tg-soft:#14212f;--tg-line:#254058}
[data-theme="dark"] .tag.teal  {--tg-ink:#6fcac5;--tg-soft:#112726;--tg-line:#1f4643}
[data-theme="dark"] .tag.green {--tg-ink:#52b98a;--tg-soft:#0e2a20;--tg-line:#1d4c39}
[data-theme="dark"] .tag.amber {--tg-ink:#dcb160;--tg-soft:#2d2415;--tg-line:#524125}
[data-theme="dark"] .tag.red   {--tg-ink:#dd8b6b;--tg-soft:#33201a;--tg-line:#5c392c}
[data-theme="dark"] .tag.purple{--tg-ink:#b49ae8;--tg-soft:#211c33;--tg-line:#3b3357}
[data-theme="dark"] .tag.pink  {--tg-ink:#e493bb;--tg-soft:#2f1a26;--tg-line:#523043}
.tags{display:flex;gap:4px;flex-wrap:wrap}
/* ป้ายที่กดได้ (หน้าจัดการ) — ที่ยังไม่ติดจางลงแต่ยังอ่านออก ไม่ใช่หายไปเลย */
button.tag{cursor:pointer}
button.tag.off{opacity:.42;background:transparent}
button.tag.off:hover{opacity:.8}
.tag .x{background:none;border:0;color:inherit;cursor:pointer;padding:0 0 0 2px;
  font-size:13px;line-height:1;opacity:.7}
.tag .x:hover{opacity:1}
.tag-dot{width:10px;height:10px;border-radius:50%;background:var(--tg-ink);
  border:1px solid var(--tg-line);display:inline-block}

/* ---------- แท็บ namespace ----------
   ไซต์ที่ดูแลหลาย namespace แยกดูทีละอันได้ ไม่ต้องเลื่อนหาในตารางเดียวยาว ๆ */
.tabs{display:flex;gap:2px;flex-wrap:wrap;margin-bottom:var(--s3);
  border-bottom:1px solid var(--line);padding-bottom:0}
.tabs .tab{display:inline-flex;align-items:center;gap:6px;background:transparent;
  border:1px solid transparent;border-bottom:0;color:var(--muted);
  border-radius:var(--r1) var(--r1) 0 0;padding:7px 12px;font-size:13px;
  margin-bottom:-1px;cursor:pointer}
.tabs .tab:hover{color:var(--ink);background:var(--panel2)}
.tabs .tab.on{color:var(--ink);background:var(--panel);border-color:var(--line);
  border-bottom:1px solid var(--panel);font-weight:600}
.tabs .tab .pill{font-size:11px;padding:1px 6px}

/* ---------- แท็บ namespace ของไซต์ blue-green ----------
   สอง namespace หน้าตาเหมือนกันหมด และกดผิดฝั่งคือไปแตะตัวที่รับงานจริงอยู่
   ขีดสีบนหัวแท็บจึงต้องเห็นตั้งแต่ยังไม่ได้เลือก ไม่ใช่เห็นตอน .on แล้ว
   (สีมาจากชุดเดียวกับ .tag ที่จับคู่สว่าง/มืดไว้แล้ว ไม่พิมพ์ค่าสีลอย ๆ) */
.tabs .tab.bg-blue,.tabs .tab.bg-green{border-top-width:3px;border-top-style:solid}
.tabs .tab.bg-blue {border-top-color:#1f5b9e}
.tabs .tab.bg-green{border-top-color:#0f7047}
.tabs .tab.bg-blue.on {color:#1f5b9e}
.tabs .tab.bg-green.on{color:#0f7047}
.pill.side{text-transform:uppercase;letter-spacing:.4px}
.pill.blue {background:#e3eefb;color:#1f5b9e;border-color:#b9d4f0}
.pill.green{background:#d8f0e4;color:#0f7047;border-color:#a3d7bf}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .tabs .tab.bg-blue {border-top-color:#6aa9e9}
  :root:not([data-theme="light"]) .tabs .tab.bg-green{border-top-color:#5fc79a}
  :root:not([data-theme="light"]) .tabs .tab.bg-blue.on {color:#8ec2f2}
  :root:not([data-theme="light"]) .tabs .tab.bg-green.on{color:#7fd8b2}
  :root:not([data-theme="light"]) .pill.blue {background:#15263a;color:#8ec2f2;border-color:#274b70}
  :root:not([data-theme="light"]) .pill.green{background:#123026;color:#7fd8b2;border-color:#1f5c43}
}
:root[data-theme="dark"] .tabs .tab.bg-blue {border-top-color:#6aa9e9}
:root[data-theme="dark"] .tabs .tab.bg-green{border-top-color:#5fc79a}
:root[data-theme="dark"] .tabs .tab.bg-blue.on {color:#8ec2f2}
:root[data-theme="dark"] .tabs .tab.bg-green.on{color:#7fd8b2}
:root[data-theme="dark"] .pill.blue {background:#15263a;color:#8ec2f2;border-color:#274b70}
:root[data-theme="dark"] .pill.green{background:#123026;color:#7fd8b2;border-color:#1f5c43}

/* ---------- กล่องตั้งค่า: แบ่งเป็นหมวดและพับได้ ----------
   ค่าตั้งเพิ่มขึ้นเรื่อย ๆ กางหมดตั้งแต่แรกแล้วจะเลื่อนหาไม่เจอ */
.panel.fold.flat{border:0;background:transparent;padding:0;margin:0 0 var(--s3);
  box-shadow:none}
.panel.fold.flat > .fold-h{padding:8px 0;border-bottom:1px solid var(--line)}
.panel.fold.flat > .fold-b{padding-top:var(--s3)}
.set-group{margin-bottom:var(--s4)}
.set-group:last-child{margin-bottom:0}
.set-group .dlg-h2{margin-top:0}

/* ---------- บรรทัดคำสั่งที่ให้คัดลอก ---------- */
.cmdline{display:inline-block;max-width:100%;overflow-x:auto;white-space:nowrap;
  vertical-align:middle;padding:4px 8px;border-radius:var(--r1);
  background:var(--panel2);border:1px solid var(--line);font-size:12px}

/* ---------- รายการห้ามแตะ ---------- */
.lock-row{display:flex;align-items:center;gap:var(--s3)}
.lock-row .k{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#lockBox .toolbar{margin-top:var(--s3)}
#lockBox select{flex:1;min-width:0}

/* ---------- ปุ่มบนมุมการ์ด (เฟือง + หมุด) ---------- */
/* เดิมเฟืองวางลอยที่มุมขวาบน พอมีสองปุ่มต้องมีที่ให้มันเรียงกัน ไม่ใช่ทับกัน */
.card-acts{position:absolute;top:var(--s3);right:var(--s3);z-index:2;
  display:flex;gap:var(--s2)}
.card-acts .gear{position:static}
.gear.pin.on{color:var(--accent);border-color:var(--accent);background:var(--accent-soft)}
.gear.pin.on svg{fill:currentColor}

/* การ์ดในหน้าหมุด — ทั้งใบเป็นลิงก์ ยกเว้นมุมที่เป็นปุ่มถอน */
.pin-go{display:block;color:inherit;text-decoration:none}
.pin-go:hover .name{color:var(--accent)}

/* ---------- เส้นทางนำทาง (เดินเข้าทีละชั้น) ---------- */
.crumbs{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;
  margin:0 0 var(--s3);font-size:12.5px;min-height:28px}
.crumbs .sep{color:var(--line)}
.crumbs b{font-weight:650}
.crumbs .sm{padding:2px 8px;min-height:24px;color:var(--muted)}
.crumbs .sm:hover{color:var(--accent)}

/* ---------- สวิตช์เปิด/ปิด ---------- */
/* checkbox จริงยังอยู่ แค่ซ่อนไว้ — คีย์บอร์ดกับ screen reader จึงใช้ได้เหมือนเดิม
   ไม่ได้วาด div ขึ้นมาใหม่แล้วดักคลิกเอง ซึ่งจะเสียพฤติกรรมพวกนั้นไปทั้งชุด */
.set-row.bool .sw{display:flex;align-items:center;gap:var(--s3);cursor:pointer;
  margin-top:2px;width:fit-content}
.sw input{position:absolute;opacity:0;width:0;height:0}
.sw .track{position:relative;flex:none;width:40px;height:22px;border-radius:999px;
  background:var(--panel2);border:1px solid var(--line);
  transition:background var(--fast), border-color var(--fast)}
.sw .track::after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;
  border-radius:50%;background:var(--muted);
  transition:transform var(--fast), background var(--fast)}
.sw input:checked + .track{background:var(--accent);border-color:var(--accent)}
.sw input:checked + .track::after{transform:translateX(18px);background:var(--on-accent)}
.sw input:focus-visible + .track{outline:2px solid var(--accent2);outline-offset:2px}
.sw .lab{font-size:12.5px;color:var(--muted);font-weight:600;
  font-variant-numeric:tabular-nums}
.sw input:checked ~ .lab{color:var(--accent)}

/* ---------- สถานะตัวรับ MQTT ---------- */
.dlg-h2{display:flex;align-items:center;gap:var(--s3);margin:var(--s5) 0 var(--s3);
  padding-top:var(--s4);border-top:1px solid var(--line);
  font-size:13px;font-weight:650}
.dlg-h2 .sm{margin-left:auto}
#mqttPills{margin-bottom:var(--s3)}
.logbox{margin:0;padding:var(--s3) var(--s4);border-radius:var(--r1);
  background:var(--panel2);border:1px solid var(--line);
  font-family:var(--mono);font-size:11.5px;line-height:1.7;color:var(--ink);
  max-height:190px;overflow:auto;white-space:pre;min-width:0}

/* ---------- หน้ารวมของที่รอดีพลอย ----------
   หนึ่งแถวคือหนึ่งแอปที่ไซต์ยังไม่ได้ใช้เลขที่ตั้งไว้ — เลขต้องอยู่ชิดขวาให้กวาดตา
   ลงมาทีเดียวได้ทั้งคอลัมน์ ไม่ใช่ไล่อ่านทีละบรรทัด */
.pend-row{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s2);
  padding:var(--s3) 0;border-bottom:1px solid var(--line);align-items:center;
  color:inherit;text-decoration:none}
.pend-row:last-child{border-bottom:0}
.pend-row:hover{background:var(--panel2)}
.pend-row .k{display:block;min-width:0}
.pend-row .v{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap}
.pend-row .vrow{margin:0}
.pend-row .vnow{font-size:17px}
.pend-row .vwant{font-size:15px}
@media (min-width:700px){
  .pend-row{grid-template-columns:minmax(0,1fr) auto}
  .pend-row .v{justify-content:flex-end}
}
.pend-h{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;
  margin-bottom:var(--s2)}

/* ---------- ตัวแก้ไฟล์ chart ของเทมเพลตแบบ zip ---------- */
/* กล่องนี้ต้องกว้างกว่ากล่องอื่น เพราะข้างในเป็นโค้ด yaml ที่ตัดบรรทัดไม่ได้ */
dialog.wide-dlg{max-width:1100px;width:min(96vw,1100px)}

.ce-grid{display:grid;grid-template-columns:minmax(150px,210px) minmax(0,1fr);
  gap:var(--s3);align-items:start}
.ce-files{display:flex;flex-direction:column;gap:2px;max-height:52vh;overflow:auto;
  background:var(--panel3);border:1px solid var(--line);border-radius:var(--r2);
  padding:var(--s2)}
.ce-f{display:flex;align-items:center;gap:var(--s2);justify-content:space-between;
  width:100%;text-align:left;background:none;border:0;border-radius:var(--r1);
  padding:6px var(--s2);color:var(--ink2);font-size:12.5px;cursor:pointer;
  min-height:var(--tap)}
.ce-f:hover{background:var(--panel2)}
.ce-f.on{background:var(--accent-soft);color:var(--accent);font-weight:600}
.ce-p{display:flex;align-items:baseline;min-width:0}
.ce-p .dg{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:0 1 auto}
.ce-p b{flex:0 0 auto;font-weight:inherit}

.ce-main{display:flex;flex-direction:column;gap:var(--s3);min-width:0}
/* ชั้นระบายสีวางซ้อนอยู่ "หลัง" ช่องพิมพ์ที่ตัวหนังสือโปร่งใส — ทั้งสองชั้นต้องใช้
   ฟอนต์ ขนาด ระยะบรรทัด และ padding ชุดเดียวกันเป๊ะ ๆ ไม่งั้นสีจะเลื่อนจากตัวอักษร */
.ce-wrap{position:relative;border:1px solid var(--line);border-radius:var(--r2);
  background:var(--panel3);overflow:hidden}
.ce-wrap>pre,.ce-wrap>textarea{
  margin:0;padding:var(--s3);border:0;font:12.5px/1.65 var(--mono);
  white-space:pre;overflow:auto;tab-size:2;
  min-height:44vh;max-height:52vh;box-sizing:border-box}
.ce-wrap>pre{position:absolute;inset:0;pointer-events:none;color:var(--ink);
  background:transparent}
.ce-wrap>textarea{position:relative;width:100%;display:block;resize:vertical;
  color:transparent;background:transparent;caret-color:var(--accent);
  -webkit-text-fill-color:transparent}
.ce-wrap>textarea::selection{background:var(--accent-soft);color:transparent}
.ce-wrap>textarea:disabled{cursor:not-allowed}
.ce-wrap>textarea:focus{outline:2px solid var(--accent-line);outline-offset:-2px}
/* โค้ดที่ถูกแปลงเป็นตัวแปรแล้ว — ต้องเห็นชัดในสายตาแรกว่าตรงไหนจะถูกแทนค่าตอนลง */
mark.cvar{background:var(--amber-soft);color:var(--amber);border-radius:4px;
  box-shadow:inset 0 0 0 1px var(--amber-line);padding:0 1px}

.ce-vars{display:flex;flex-direction:column;gap:4px;max-height:26vh;overflow:auto}
.ce-v{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;width:100%;
  text-align:left;background:var(--panel3);border:1px solid var(--line);
  border-radius:var(--r1);padding:6px var(--s3);cursor:pointer;color:var(--ink2);
  font-size:12.5px;min-height:var(--tap)}
.ce-v:hover{border-color:var(--accent-line);background:var(--accent-soft)}
.ce-v .b{font-weight:650;color:var(--amber)}

.varbar{background:var(--accent-soft);border:1px solid var(--accent-line);
  border-radius:var(--r2);padding:var(--s3);margin:0 0 var(--s3);
  display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:var(--s2)}
.varbar .wide{grid-column:1/-1}
.varbar .toolbar{grid-column:1/-1;margin:0}
.toolbar .sep{flex:1}

@media (max-width:700px){
  .ce-grid{grid-template-columns:1fr}
  .ce-files{max-height:22vh;flex-direction:row;overflow-x:auto}
  .ce-f{width:auto;flex:0 0 auto}
}

/* แถบชุดค่าที่หน้าทบทวน — เรียงแนวนอนให้ป้ายกำกับไม่ถูกบีบจนขึ้นบรรทัดใหม่กลางคำ
   (กริด auto-fit ของ .varbar บีบช่องแรกจนคำว่า "วิซาร์ด/เลือกให้" แยกกันคนละบรรทัด) */
.varbar.setbar{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--s3)}
.varbar.setbar>.note{flex:1 0 100%;margin:0}
.varbar.setbar>label{flex:0 1 auto;min-width:0}
.varbar.setbar>label select,.varbar.setbar>label input{min-width:160px}
.varbar.setbar>.grow{flex:1 1 180px;align-self:center}
@media (max-width:700px){
  .varbar.setbar>label,.varbar.setbar>button{flex:1 1 100%}
}

/* ---- ปลายทางที่ถูกกดมาจากแผง "กำลังทำอยู่" ----
   ตัวบอกงานบนแถบหัวถูกถอดออกแล้ว เหลือแต่เอฟเฟกต์ปลายทาง: เลื่อนไปถึงแล้ว
   ต้องเห็นชัดว่าอันไหน ไม่ใช่เลื่อนไปแล้วให้หาต่อเอง */
@keyframes procflash{from{box-shadow:0 0 0 2px var(--accent)}to{box-shadow:none}}
.procflash{animation:procflash 1.6s ease-out}
@media (prefers-reduced-motion:reduce){.procflash{animation:none;
  outline:2px solid var(--accent)}}

/* ท้าย log ของ build ที่ล้ม บนแผงงาน */
.runlog{margin-top:4px}
.runlog summary{cursor:pointer;font-size:12px}
.runlog pre{font-family:var(--mono);font-size:11px;white-space:pre-wrap;overflow-wrap:anywhere;
  max-height:32vh;overflow:auto;margin:4px 0 0;padding:6px 8px;border-radius:6px;
  background:var(--bg2,rgba(127,127,127,.08))}

/* กุญแจภายนอกที่ใช้ไม่ได้ — ในแผงซ้าย */
.rhealth{margin:6px 8px 4px;padding:6px 8px;border-radius:8px;
  background:rgba(224,120,60,.12);border:1px solid rgba(224,120,60,.35)}
.rh{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--warn,#d9822b);padding:2px 0}
.rh svg{width:14px;height:14px;flex:none}
@media (max-width:900px){.rhealth{display:none}}
