/* ═══ tool.css — โครงกลางของเครื่องมือทุกตัว (ไม่ผูกแบรนด์) ═══════════════
   🔴 แก้ที่นี่ที่เดียว ห้ามคัดลอกไปไว้ในหน้าใดหน้าหนึ่ง · ห้ามมี hex ในไฟล์นี้ (อยู่ใน tokens.css)
   สัญญาที่หน้าเดิมใช้: header .brand h1 .model .dot #state · button .pri .ghost · main .card .wide h2
   .uid .meta .row .f label input select .lamps #log .note .bad — คงไว้ทุกตัว
   เพิ่มสำหรับแม่แบบตั้งค่า: .app .side .nav .ttl .grid .pc details.lg · ปุ่ม .sec .danger
   เพิ่มสำหรับหน้ารวม: .pick .wrap a.m .t .s .d .grp .lead .tail
   ลูกเล่นของแบรนด์ (โฟกัสแบบไหน กดย่อไหม กระจกฝ้า) อยู่ใน _design/<brand>/behaviors.css ซึ่ง build ต่อท้ายไฟล์นี้ */
@import url("/tokens.css");

*{box-sizing:border-box}
html,body{max-width:100%;overflow-x:hidden}       /* กันหน้าเลื่อนแนวนอน — วัดการล้นต้องวัดขอบ element ไม่ใช่ scrollWidth */
body{margin:0;background:var(--canvas);color:var(--ink);font-family:var(--font);
 font-size:var(--type-body-sm-size);line-height:var(--type-body-sm-lh);letter-spacing:var(--type-body-sm-ls)}   /* {typography.body-sm} */
img,svg{max-width:100%;height:auto}
svg[hidden]{display:none}   /* hidden ไม่มีผลกับ SVG โดยตัวมันเอง — คลังไอคอนจะกินที่ ~150px */
a{color:var(--link)}
a:hover{color:var(--link-hover)}

/* ── top-nav: canvas · 48px · เส้นล่าง hairline ── */
header{background:var(--comp-top-nav-bg);color:var(--comp-top-nav-ink);min-height:var(--comp-top-nav-height);padding:4px var(--sp-4);   /* {component.top-nav} */
 display:flex;align-items:center;gap:4px var(--sp-4);flex-wrap:wrap;border-bottom:1px solid var(--hairline)}
header .brand{background:#fff;border:1px solid var(--hairline);border-radius:var(--r);padding:4px 6px;display:flex;align-items:center;flex:none}
header img{height:18px;display:block}
header h1{margin:0;font:var(--comp-top-nav-font);flex:1;min-width:180px;display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap}
header .model{background:var(--comp-utility-bar-bg);color:var(--comp-utility-bar-ink);font:var(--comp-utility-bar-font);letter-spacing:var(--type-caption-ls);   /* {component.utility-bar} */
padding:4px 8px;border-radius:var(--r)}
header select{width:auto;min-height:32px;padding:4px 8px;font-size:12px}   /* ช่องเลือกบนแถบ (ถ้ามี) */
.dot{width:8px;height:8px;border-radius:var(--r);background:var(--toggle-off);display:inline-block;margin-right:6px}
.dot.on{background:var(--success)}
#state{font-size:var(--type-caption-size);letter-spacing:var(--type-caption-ls);color:var(--ink-muted);display:flex;align-items:center}

/* ── ปุ่ม: typography.button 14/400/.16 · 12×16 · มุม 0 ──
   ค่าเริ่มต้น = tertiary (ขาว ขอบ+ตัวน้ำเงิน) · .pri primary · .sec ink · .ghost ตัวอย่างเดียว · .danger error */
button{font:var(--comp-button-tertiary-font);letter-spacing:var(--type-button-ls);cursor:pointer;   /* {component.button-tertiary} */
 border-radius:var(--comp-button-tertiary-rounded);border:1px solid var(--btn-tertiary);background:transparent;color:var(--btn-tertiary);
 padding:var(--comp-button-tertiary-padding);min-height:var(--tap);transition:background .1s,color .1s,border-color .1s}
button:hover{background:var(--btn-tertiary-hover);border-color:var(--btn-tertiary-hover);color:var(--btn-tertiary-ink-hover)}   /* [buttonTertiary*] */
button:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
button.pri{background:var(--comp-button-primary-bg);color:var(--comp-button-primary-ink);border-color:transparent}   /* {component.button-primary} */
button.pri:hover{background:var(--blue-hover)}
button.pri:active{background:var(--comp-button-primary-pressed-bg)}
/* 🔴 ปุ่มรองต้องมีขอบ ไม่งั้นแยกจากพื้นการ์ดไม่ออก
   วัดจริงบนธีมมืด: พื้นปุ่ม #424242 บนพื้นการ์ด #212121 ได้ 1.60 · เกณฑ์ขอบคือ 3.0
   🔴 คอมเมนต์ต้องอยู่เหนือกฎ ห้ามแทรกกลาง selector
      เคยพลาด: ใส่ไว้ระหว่าง button กับ .sec เลยกลายเป็น "button .sec" ซึ่งไม่ตรงกับอะไรเลย
      กฎเงียบหายไปทั้งข้อ หน้าเว็บยังขึ้นปกติ ไม่มีอะไรฟ้อง */
button.sec{background:var(--btn-secondary);color:var(--comp-button-secondary-ink);border-color:var(--hairline-strong)}   /* {component.button-secondary} */
button.sec:hover{background:var(--btn-secondary-hover)}   /* [buttonSecondary buttonSecondaryHover] */
button.ghost{background:transparent;color:var(--comp-button-ghost-ink);border-color:transparent}   /* {component.button-ghost} */
button.ghost:hover{background:var(--surface-hover);color:var(--link)}
button.danger{background:var(--comp-button-danger-bg);color:var(--comp-button-danger-ink);border-color:transparent}   /* {component.button-danger} */
button.danger:hover{background:var(--btn-danger-hover)}
button.danger:active{background:var(--btn-danger-active)}
button:disabled,button[disabled],button.pri:disabled,button.sec:disabled,button.danger:disabled{
 background:var(--btn-disabled);color:var(--btn-disabled-ink);border-color:transparent;cursor:not-allowed}   /* [buttonDisabled textOnColorDisabled] */
button.ghost:disabled{background:transparent}

/* ── ช่องกรอก: text-input — surface-1 · เส้นล่าง 1px · โฟกัส = เส้นล่าง 2px primary + outline ── */
label{font-size:var(--type-caption-size);line-height:var(--type-caption-lh);letter-spacing:var(--type-caption-ls);font-weight:var(--type-caption-weight);color:var(--ink-muted);display:block;margin-bottom:var(--sp-2)}
input,select{font:var(--comp-text-input-font);letter-spacing:var(--type-body-ls);color:var(--comp-text-input-ink);   /* {component.text-input} */
 background:var(--comp-text-input-bg);border:1px solid var(--hairline);border-radius:var(--comp-text-input-rounded);
 padding:var(--comp-text-input-padding);min-height:var(--tap);width:100%}
input:focus,select:focus{outline:2px solid var(--focus);outline-offset:1px}
input::placeholder{color:var(--placeholder)}   /* [textPlaceholder] */
input:hover,select:hover{background:var(--surface-hover)}   /* [fieldHover01] */
input[type=range]{border:0;background:transparent;padding:0;min-height:0;accent-color:var(--primary)}
input[type=checkbox]{width:auto;min-height:0;padding:0;border:0;accent-color:var(--primary)}

/* ── กล่อง: feature-card — canvas · 1px hairline · 24 · ไม่มีเงา ── */
main{max-width:1312px;margin:var(--sp-6) auto;padding:0 var(--sp-8);display:grid;gap:var(--sp-4);grid-template-columns:1fr 1fr}
.card{background:var(--comp-feature-card-bg);color:var(--comp-feature-card-ink);border:1px solid var(--hairline);border-radius:var(--comp-feature-card-rounded);padding:var(--comp-feature-card-padding);min-width:0}   /* {component.feature-card} */
.card.wide{grid-column:1/-1}
h2{margin:0 0 var(--sp-3);font:var(--type-body-emphasis-weight) var(--type-body-emphasis-size)/var(--type-body-emphasis-lh) var(--font);letter-spacing:var(--type-body-emphasis-ls);color:var(--ink)}
h3{margin:0 0 var(--sp-3);font:var(--type-eyebrow-weight) var(--type-eyebrow-size)/var(--type-eyebrow-lh) var(--font);letter-spacing:var(--type-eyebrow-ls);color:var(--ink-muted)}   /* {typography.eyebrow} */
.meta{display:flex;gap:var(--sp-4);flex-wrap:wrap;margin-top:var(--sp-3);font-size:12px;letter-spacing:var(--ls-caption);color:var(--ink-muted)}
.row{display:flex;gap:var(--sp-2);flex-wrap:wrap;align-items:center;margin-top:var(--sp-3)}
.f{flex:1;min-width:110px}
/* feature-card-elevated: surface-1 + แถบซ้าย — หมายเหตุ */
.note{background:var(--comp-feature-card-elevated-bg);border:1px solid var(--hairline);border-radius:var(--comp-feature-card-elevated-rounded);color:var(--ink-muted);
 padding:var(--sp-4) var(--sp-6);font-size:var(--type-body-sm-size);line-height:var(--type-body-sm-lh);margin-top:var(--sp-3)}   /* {component.feature-card-elevated} */
.note b{color:var(--ink);font-weight:600}
.note code{background:var(--canvas);color:var(--ink);border:1px solid var(--hairline);border-radius:var(--r);padding:1px 6px;font-size:12px;font-family:var(--mono)}
.note+.note{margin-top:var(--sp-2)}
.bad{border-color:var(--error)}

/* ── UID / ตัวเลขใหญ่ (RFID): display-md 42/300 บน surface-1 ── */
.uid{font:var(--type-display-md-weight) clamp(24px,4.6vw,var(--type-display-md-size))/var(--type-display-md-lh) var(--mono);   /* {typography.display-md} */letter-spacing:.04em;color:var(--ink);background:var(--surface-1);
 border:1px solid var(--hairline);border-radius:var(--r);padding:var(--sp-4);text-align:center;word-break:break-all;
 min-height:74px;display:flex;align-items:center;justify-content:center}
.uid.empty{color:var(--ink-subtle);font:400 14px/1.29 var(--font);letter-spacing:var(--ls-body)}

/* ── ไฟ/เสียง (RFID): แถวละสี ── */
.lamps{display:grid;grid-template-columns:auto 1fr 1fr;gap:var(--sp-2) var(--sp-3);align-items:center}
.lamps .lname{font-size:14px;font-weight:600;display:flex;align-items:center;gap:var(--sp-2);padding-right:4px}
.lamps .sw{width:10px;height:10px;border-radius:var(--r);display:inline-block}
.lamps .sw.r{background:var(--error)}.lamps .sw.g{background:var(--success)}.lamps .sw.b{background:var(--warning)}
.lamps button{border-color:var(--hairline);background:var(--canvas);color:var(--ink)}
.lamps button:hover{background:var(--surface-hover);color:var(--ink)}

/* ── บันทึกการสื่อสาร: inverse-canvas ── */
#log{font:12px/1.6 var(--mono);letter-spacing:var(--ls-caption);background:var(--inverse-canvas);color:var(--inverse-ink-muted);
 border-radius:var(--r);padding:var(--sp-4);height:clamp(150px,32vh,230px);overflow:auto;white-space:pre-wrap;word-break:break-all;max-width:100%}
#log .tx{color:var(--log-tx)}#log .rx{color:var(--log-rx)}#log .er{color:var(--log-er)}#log .in{color:var(--log-in)}

/* ── แม่แบบตั้งค่า: แถบข้าง + การ์ดค่า ── */
main.app-main{display:block;padding:0}
.app{display:grid;grid-template-columns:256px minmax(0,1fr);gap:var(--sp-6);max-width:1312px;margin:var(--sp-6) auto var(--sp-12);padding:0 var(--sp-8);min-width:0}
.app>*{min-width:0}
.side{position:sticky;top:var(--sp-4);align-self:start;display:flex;flex-direction:column;gap:var(--sp-4)}
.side .card{margin:0;padding:var(--sp-4)}
.side .f{margin-bottom:var(--sp-4)}
.side .act{display:flex;flex-direction:column;gap:var(--sp-2);margin-top:var(--sp-2)}
.side .act button{width:100%;text-align:left}
.sw-row{display:flex;align-items:center;gap:var(--sp-2);font-size:14px;color:var(--ink-muted);cursor:pointer;margin-top:var(--sp-4)}
/* product-tab แนวตั้ง: ink-muted · เลือกแล้ว = ink 600 + เส้นซ้าย 2px primary */
.nav{display:flex;flex-direction:column;gap:4px}
.nav button{display:flex;align-items:center;gap:var(--sp-2);width:100%;text-align:left;background:var(--comp-product-tab-bg);color:var(--comp-product-tab-ink);font:var(--comp-product-tab-font);   /* {component.product-tab} */
 padding:var(--sp-3) var(--sp-4);border:1px solid transparent;border-radius:var(--r);min-height:48px;box-shadow:none} */
 padding:var(--sp-3) var(--sp-4) var(--sp-3) 14px;border:0;border-bottom:1px solid var(--hairline);border-left:2px solid transparent;min-height:48px}
.nav button:hover{background:var(--surface-hover);color:var(--ink)}
.nav button.on,.nav button.on:hover{background:var(--surface-1);color:var(--comp-product-tab-selected-ink);font:var(--comp-product-tab-selected-font)}   /* {component.product-tab-selected} */
.nav .k{margin-left:auto;font-size:12px;letter-spacing:var(--ls-caption);font-weight:400;color:var(--ink-subtle);font-variant-numeric:tabular-nums}
.ttl{display:flex;align-items:baseline;gap:var(--sp-4);margin:0 0 var(--sp-4)}
.ttl h2{margin:0;font:var(--type-headline-weight) var(--type-headline-size)/var(--type-headline-lh) var(--font);letter-spacing:var(--type-headline-ls)}   /* {typography.headline} */
.ttl .cnt{font-size:14px;color:var(--ink-muted);margin-left:auto;font-variant-numeric:tabular-nums}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(272px,1fr));gap:var(--sp-4)}
.pc{background:var(--canvas);border:1px solid var(--hairline);border-radius:var(--r);padding:var(--sp-6);display:flex;flex-direction:column;gap:var(--sp-2);min-width:0}
.pc .nm{font:var(--type-body-emphasis-weight) var(--type-body-emphasis-size)/var(--type-body-emphasis-lh) var(--font);display:flex;gap:var(--sp-2);align-items:center}
.pc .nm .reg{font:400 12px/1.33 var(--mono);letter-spacing:var(--ls-caption);color:var(--ink-muted);background:var(--surface-1);padding:2px 8px;margin-left:auto}
.pc .hint{font-size:var(--type-caption-size);line-height:var(--type-caption-lh);letter-spacing:var(--type-caption-ls);color:var(--ink-muted);min-height:2.7em}
.pc .val{display:flex;align-items:baseline;gap:var(--sp-2);margin:var(--sp-3) 0 var(--sp-2)}
.pc .big{font:var(--type-display-md-weight) var(--type-display-md-size)/var(--type-display-md-lh) var(--font);letter-spacing:var(--type-display-md-ls);font-variant-numeric:tabular-nums}   /* {typography.display-md} */
.pc .big.none{color:var(--ink-subtle)}
.pc .unit{font-size:14px;color:var(--ink-muted)}
.pc .ro{font-size:12px;letter-spacing:var(--ls-caption);color:var(--ink-muted);background:var(--surface-1);padding:2px 8px;margin-left:auto}
.pc .ed{display:flex;flex-wrap:wrap;gap:var(--sp-2);margin-top:auto}
.pc .ed input{flex:1 1 100px;min-width:100px;font-family:var(--mono);letter-spacing:0}
.pc .ed button{min-height:var(--tap);padding:var(--sp-2) var(--sp-4)}
.pc.chg{border-color:var(--primary);box-shadow:inset 0 0 0 1px var(--primary)}
.pc.err{border-color:var(--error);box-shadow:inset 0 0 0 1px var(--error)}
details.lg{margin-top:var(--sp-6);min-width:0}
details.lg summary{cursor:pointer;color:var(--link);font-size:14px;padding:var(--sp-3) 0;list-style:none;display:flex;gap:var(--sp-2);align-items:center}
details.lg summary::-webkit-details-marker{display:none}
details.lg summary::after{content:"›";font-size:18px;line-height:1;transition:transform .1s}
details.lg[open] summary::after{transform:rotate(90deg)}
details.lg summary .last{font:400 12px/1.33 var(--mono);color:var(--ink-subtle);margin-left:auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:55%}
.grid+.note{margin-top:var(--sp-6)}

/* ── หน้ารวม (เลือกรุ่น / เลือกเครื่องมือ) ── */
.pick,.wrap{max-width:840px;margin:var(--sp-6) auto var(--sp-12);padding:0 var(--sp-8)}
.pick h2,.wrap h2{font:var(--type-headline-weight) var(--type-headline-size)/var(--type-headline-lh) var(--font);margin:0 0 var(--sp-2)}
p.lead{margin:0 0 var(--sp-6);color:var(--ink-muted);font-size:var(--type-body-size);line-height:var(--type-body-lh);letter-spacing:var(--type-body-ls)}
.grp{font-size:14px;font-weight:400;color:var(--ink-muted);margin:var(--sp-6) 0 var(--sp-2)}
a.m{display:block;background:var(--canvas);border:1px solid var(--hairline);border-radius:var(--r);padding:var(--sp-4) var(--sp-6);
 margin-bottom:var(--sp-2);text-decoration:none;color:var(--ink)}
a.m:hover{background:var(--surface-hover)}
a.m .t{font:var(--type-subhead-weight) var(--type-subhead-size)/var(--type-subhead-lh) var(--font);color:var(--ink)}   /* {typography.subhead} */
a.m .s{font-size:12px;letter-spacing:var(--ls-caption);color:var(--link);margin-left:var(--sp-2)}
a.m .d{font-size:14px;color:var(--ink-muted);margin-top:var(--sp-1);line-height:1.43}
.tail{font-size:14px;color:var(--ink-muted);line-height:1.5;margin-top:var(--sp-6);border-top:1px solid var(--hairline);padding-top:var(--sp-4)}

/* ── จอแคบ ── */
@media(max-width:820px){main{grid-template-columns:1fr}}
@media(max-width:760px){
  .app{grid-template-columns:minmax(0,1fr);gap:var(--sp-4);margin-top:var(--sp-4);padding:0 var(--sp-4)}
  .side{position:static}
  .nav{flex-direction:row;flex-wrap:wrap;gap:8px}
  .nav button{width:auto;border:1px solid var(--hairline)}
  .side .act{flex-direction:row;flex-wrap:wrap}
  .side .act button{width:auto;flex:1}
  .side .conn{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-4)}
  .side .conn .f{margin:0}
  .ttl h2{font-size:24px;line-height:1.33}
  .grid{grid-template-columns:repeat(auto-fill,minmax(168px,1fr));gap:var(--sp-3)}
  .pc{padding:var(--sp-4)}
  .pc .big{font-size:32px;line-height:1.25}
  .pc .hint{min-height:0}
  .pc .ed input{flex-basis:100%;min-width:0}
  .pick,.wrap{padding:0 var(--sp-4)}
}
@media(max-width:640px){
  main{padding:0 var(--sp-4)}
  header h1{order:-1;flex:1 0 100%}
  header #proto{flex:1 1 100%}
  header #state{order:3}
  header button{flex:1 1 auto}
  .row>div.f,.row>div[class*="f"]{min-width:0;flex:1 1 100%}
  .row>button{flex:1 1 100%}
  .lamps{grid-template-columns:1fr 1fr}
  .lamps .lname{grid-column:1/-1;padding-top:4px}
  button,input,select{min-height:48px}      /* เป้าแตะ 48 (Carbon) */
}

/* ── แถบบนแบบ ESPConnect: เชื่อมต่อ/ตัด + baud + ที่อยู่ + ป้ายสถานะขวา + สลับธีม ── */
header.bar{gap:var(--sp-2) var(--sp-4)}
header.bar h1{flex:0 1 auto;min-width:0}
.conn-bar{display:flex;align-items:center;gap:var(--sp-2);flex:1 1 auto;flex-wrap:wrap}
label.inline{display:flex;align-items:center;gap:6px;margin:0;font-size:12px;color:var(--ink-muted)}
label.inline input,label.inline select{width:auto;min-height:36px;padding:6px 10px;font-size:14px}
label.inline input{width:76px}
.pill{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border:1px solid var(--hairline);border-radius:var(--r-pill);font-size:12px;color:var(--ink-muted);background:var(--surface-1)}
.pill.on{color:var(--ink);border-color:var(--success)}
.ic{width:18px;height:18px;flex:none;vertical-align:-4px}
.ic.big{width:40px;height:40px;color:var(--ink-subtle)}
button .ic{margin-right:6px}
button.icon{padding:8px;min-width:var(--tap);justify-content:center}
button.icon .ic{margin:0}
.nav button .ic{color:var(--ink-subtle);margin-right:2px}
.nav button.on .ic{color:var(--primary)}
/* สถานะว่างก่อนเชื่อมต่อ */
.empty{display:flex;flex-direction:column;align-items:center;gap:var(--sp-2);text-align:center;padding:var(--sp-12) var(--sp-6);
 background:var(--canvas);border:1px solid var(--hairline);border-radius:var(--comp-feature-card-rounded);color:var(--ink-muted);max-width:560px;margin:var(--sp-8) auto}
.empty b{color:var(--ink);font-size:16px}
.empty .hint{font-size:12px;color:var(--ink-subtle)}
/* ไทล์แบบ Home Assistant: ไอคอน + ชื่อ + สถานะ · 2 คอลัมน์ · stepper ข้างใน */
.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:var(--sp-3)}
.tile{background:var(--comp-feature-card-bg);border:1px solid var(--hairline);border-radius:var(--comp-feature-card-rounded);padding:var(--sp-3) var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-2);min-width:0}
.tile .tl{display:flex;align-items:center;gap:var(--sp-3)}
.tile .tico{width:40px;height:40px;flex:none;display:grid;place-items:center;background:var(--surface-1);border-radius:var(--r);color:var(--primary)}
.tile.ro .tico{color:var(--ink-muted)}
.tile .tt{flex:1;min-width:0}
.tile .nm{font:var(--type-body-emphasis-weight) var(--type-body-emphasis-size)/var(--type-body-emphasis-lh) var(--font);display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.tile .nm .reg{font:400 11px/1.3 var(--mono);color:var(--ink-subtle);background:var(--surface-1);padding:1px 6px}
.tile .st{font-size:var(--type-body-sm-size);color:var(--ink-muted);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tile .st b{font-size:18px;font-weight:400;color:var(--ink);font-variant-numeric:tabular-nums}
.tile .st .unit{color:var(--ink-muted)}
.tile .st .age{color:var(--ink-subtle);font-size:12px}
.tile.unread .st b{color:var(--ink-subtle)}
.tile .hint{font-size:12px;line-height:1.35;letter-spacing:var(--ls-caption);color:var(--ink-subtle)}
.tile button.r{min-height:32px;min-width:32px;padding:4px;font-size:16px}
.tile .step{display:flex;align-items:center;gap:6px;margin-top:2px}
.tile .step input{flex:1;min-width:0;text-align:center;font-family:var(--mono);min-height:var(--tap);padding:6px 8px}
.tile .step button.m{min-width:var(--tap);min-height:var(--tap);padding:0;font-size:18px;border:1px solid var(--hairline)}
.tile .step button.w{min-height:var(--tap);padding:0 var(--sp-4)}
.tile.chg{border-color:var(--primary);box-shadow:inset 0 0 0 1px var(--primary)}
.tile.err{border-color:var(--error);box-shadow:inset 0 0 0 1px var(--error)}
/* บันทึกเหตุการณ์ (ล่าสุดบน) */
.events{display:flex;flex-direction:column;border:1px solid var(--hairline);background:var(--canvas);max-height:60vh;overflow:auto}
.ev{display:flex;gap:var(--sp-3);padding:var(--sp-2) var(--sp-4);border-bottom:1px solid var(--hairline);font-size:var(--type-body-sm-size)}
.ev .t{font-family:var(--mono);color:var(--ink-subtle);flex:none}
.ev.er .m{color:var(--error)}
#view[hidden],#viewMon[hidden],#viewEvents[hidden],#rawRow[hidden],#empty[hidden]{display:none}
@media(max-width:760px){
  .conn-bar{order:5;flex:1 1 100%}
  .tiles{grid-template-columns:1fr}
  .empty{padding:var(--sp-8) var(--sp-4)}
}

/* ── แผนผังอุปกรณ์ (devices/) — การ์ดต่ออุปกรณ์ + แถบแผนที่รีจิสเตอร์ของตัวนั้น ── */
.app.devmap{grid-template-columns:minmax(0,1fr) 320px}
.app.devmap .side{gap:var(--sp-4)}
.devs{display:flex;flex-direction:column;gap:var(--sp-3)}
.dev{background:var(--comp-feature-card-bg);border:1px solid var(--hairline);border-radius:var(--comp-feature-card-rounded);padding:var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-2);min-width:0}
.dev header{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap}
.dev .ad{flex:none;width:34px;height:34px;display:grid;place-items:center;border-radius:var(--r);background:var(--c);color:var(--ci);font:600 16px/1 var(--mono)}
.dev .hd{flex:1;min-width:140px;display:flex;flex-direction:column;gap:1px}
.dev .hd b{font:var(--type-body-emphasis-weight) var(--type-body-emphasis-size)/1.3 var(--font)}
.dev .hd small,.dev .mn{font-size:12px;color:var(--ink-muted)}
.dev .st{font-size:12px;color:var(--ink-subtle);white-space:nowrap}.dev .st.on{color:var(--success)}.dev .st.off{color:var(--error)}
.dev .lk{font-size:12px;text-decoration:none;white-space:nowrap}
.dev .warn{font-size:12px;color:var(--error);border:1px solid var(--error);border-radius:var(--r);padding:6px 10px}
/* แถบแผนที่รีจิสเตอร์: ความกว้างตามจำนวนรีจิสเตอร์ */
.rmap{display:flex;gap:2px;min-height:46px;border-radius:var(--r);overflow:hidden}
.rmap i{min-width:56px;display:flex;flex-direction:column;justify-content:center;gap:1px;padding:6px 8px;font-style:normal;overflow:hidden}
.rmap i b{font:600 12px/1.2 var(--font);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rmap i small{font:11px var(--mono);opacity:.8;white-space:nowrap}
.rmap .k-rw{background:var(--c);color:var(--ci)}
.rmap .k-ro{background:var(--c);color:var(--ci);opacity:.55}
.rmap .k-unused{background:var(--surface-2);color:var(--ink-muted)}
.rmap .k-unknown{background:repeating-linear-gradient(45deg,var(--surface-2),var(--surface-2) 6px,transparent 6px,transparent 12px);color:var(--ink-muted);border:1px dashed var(--border-strong)}
.rsum{font-size:12px;color:var(--ink-muted)}.rsum .q{color:var(--warning)}
.rt{width:100%;border-collapse:collapse;font-size:12.5px;display:block;overflow-x:auto}
.rt tbody{display:table;width:100%}
.rt td{padding:5px 8px;border-bottom:1px solid var(--hairline);vertical-align:top}
.rt td:first-child{white-space:nowrap;width:1%}.rt td:nth-child(3){text-align:right;width:1%;color:var(--ink-muted)}.rt td:last-child{width:1%}
.rt tr:last-child td{border-bottom:0}.rt .mono{font-family:var(--mono)}.rt small{color:var(--ink-subtle)}
.rt tr.k-unknown td,.rt tr.k-unused td{color:var(--ink-subtle)}
.kb{font-size:11px;padding:1px 7px;border-radius:var(--r-pill);white-space:nowrap;background:var(--surface-2);color:var(--ink-muted)}
.kb.k-rw{background:var(--c);color:var(--ci)}.kb.k-ro{border:1px solid var(--border-strong);background:transparent}
.kb.k-unknown{border:1px dashed var(--warning);background:transparent;color:var(--warning)}
.businfo{display:flex;flex-direction:column;gap:var(--sp-2)}
.bg{display:flex;align-items:center;gap:var(--sp-2);font-size:12px}.bg b{font-family:var(--mono);color:var(--ink-muted);min-width:82px}
.bg span{display:flex;gap:4px;flex-wrap:wrap}.bg i{display:grid;place-items:center;width:24px;height:24px;border-radius:var(--r);font:600 12px var(--mono);font-style:normal}
.robot{width:100%;max-width:280px;display:block;margin:0 auto}
.robot .body{fill:var(--surface-1);stroke:var(--hairline-strong);stroke-width:2}.robot .nose{fill:none;stroke:var(--ink-muted);stroke-width:2}.robot .wheel{fill:var(--ink-subtle)}
.robot .addr{font:600 14px var(--mono);text-anchor:middle}.robot .lbl{font:12px var(--font);fill:var(--ink);text-anchor:middle}
.robot .pin.off circle{opacity:.3}.robot .pin.on circle{stroke:var(--success);stroke-width:3}
.legend{display:flex;gap:12px;flex-wrap:wrap;margin-top:var(--sp-3);font-size:12px;color:var(--ink-muted)}
.legend i{display:inline-block;width:12px;height:12px;border-radius:var(--r);vertical-align:-1px;margin-right:5px}
@media(max-width:760px){
  .app.devmap{grid-template-columns:minmax(0,1fr)}
  .rmap{flex-wrap:wrap;min-height:0}.rmap i{flex:1 1 100px!important;min-width:100px}
  .dev .hd{flex:1 1 100%}
}
/* ═══ behaviors.css — ลูกเล่นประจำตัว ESPConnect / Vuetify Material ═══ */
/* ปุ่ม: ตัวพิมพ์ใหญ่ 14/500 ระยะ .089em · สูง 36 · outlined = โปร่ง ขอบ+ตัว primary · hover = ทับ 8% (Material overlay) */
button{text-transform:uppercase;letter-spacing:var(--type-button-ls);font-weight:500;min-height:36px;border-radius:var(--rounded-md);transition:background .15s,color .15s,box-shadow .15s}
button:hover{background:var(--btn-tertiary-hover);color:var(--primary);border-color:var(--primary)}
button.pri{box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}   /* v-btn elevated 2 */
button.pri:hover{background:var(--blue-hover);color:var(--color-on-primary)}
/* เชื่อมต่อ = outlined primary ตามต้นแบบ (ไม่ใช่ทึบ) */
#btnConn{background:transparent;color:var(--primary);border:1px solid var(--primary);box-shadow:none}
#btnConn:hover{background:var(--btn-tertiary-hover)}
/* ตัดการเชื่อมต่อ = outlined error (แบบ ESPConnect) */
#btnDisc{color:var(--error);border-color:var(--error)}
#btnDisc:hover{background:rgba(207,102,121,.12);color:var(--error)}
button:focus-visible{outline:0;box-shadow:0 0 0 3px rgba(33,150,243,.35)}
button:disabled,button:disabled:hover{box-shadow:none}
/* ช่องกรอก outlined: ขอบ .38 → โฟกัสขอบ 2px primary (v-field outlined) */
input,select{border:1px solid var(--border-strong);background:transparent}
input:focus,select:focus{outline:0;border-color:var(--primary);box-shadow:inset 0 0 0 1px var(--primary)}
input:hover,select:hover{background:transparent;border-color:var(--ink)}
/* แถบบน = app-bar 64px surface · แถบข้าง = nav-drawer surface · เมนู = list-item 40px มุม 4 · เลือกแล้ว = surface-light + ไอคอน primary */
header{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12);border-bottom:0}
.side .card{background:var(--comp-nav-drawer-bg)}
.side h3{text-transform:uppercase;letter-spacing:var(--type-overline-ls);font-size:12px;font-weight:500;color:var(--ink-muted)}
.nav{gap:2px}
.nav button{text-transform:none;letter-spacing:var(--ls-body);font-weight:400;min-height:40px;border-radius:var(--rounded-md);color:var(--ink-muted)}
.nav button:hover{background:var(--surface-hover);color:var(--ink);border-color:transparent}
.nav button.on,.nav button.on:hover{background:var(--comp-list-item-active-bg);color:var(--ink);font-weight:500}
.nav button.on .ic{color:var(--primary)}
/* ป้ายสถานะ = v-chip: surface-light pill 32px */
.pill{background:var(--comp-chip-status-bg);border:0;min-height:32px;color:var(--ink);padding:0 12px}
.pill.on{color:var(--success)}
/* การ์ด: surface ไม่มีเงา · สถานะว่างเป็นการ์ดยกระดับ (surface-light) */
.card,.tile,.note{border-color:var(--hairline)}
.empty{background:var(--comp-empty-state-card-bg);border:0;color:var(--ink-muted)}
.empty b{color:var(--ink)}
.note{border:0;border-left:3px solid var(--primary);background:var(--comp-card-elevated-bg);color:var(--ink-muted)}
.bad{border-left-color:var(--error)}
/* จอมอนิเตอร์ = console บน canvas · ไอคอนไทล์บน surface-light */
#log{background:var(--comp-console-bg);border:1px solid var(--hairline)}
.tile .tico{background:var(--comp-card-elevated-bg)}
.dot{border-radius:50%}
