/* ============================================================
   เกษตรไทย IoT — app UI (register: product)
   GitHub-repo energy: dark, dense, card-based, Thai-first.
   Tokens inherited from iot-server-frontend / mockup.html so the
   whole platform reads as one system.
   ============================================================ */
:root {
  /* surfaces */
  --bg:        #0e1116;
  --surface:   #161b22;
  --surface-2: #1c2230;
  --surface-3: #232b3a;
  --border:    #2b3240;
  --border-strong: #3a4354;

  /* ink */
  --text:   #e6edf3;
  --muted:  #9aa4b2;   /* ≥4.5:1 on --surface */
  --faint:  #7b8494;   /* large / non-essential only */

  /* brand + state */
  --accent:       #2f81f7;
  --accent-hover: #4b93f9;
  --accent-press: #1f6feb;
  --accent-soft:  rgba(47,129,247,.14);
  --ring:         rgba(47,129,247,.42);

  --ok:    #3fb950;  --ok-soft:   rgba(63,185,80,.14);
  --warn:  #d29922;  --warn-soft: rgba(210,153,34,.15);
  --crit:  #f85149;  --crit-soft: rgba(248,81,73,.14);
  --off:   #6b7689;  --off-soft:  rgba(107,118,137,.16);
  --info:  #39d3f5;

  /* type */
  --sans: "Segoe UI", system-ui, -apple-system, Roboto, "Noto Sans Thai", "Noto Sans", sans-serif;
  --mono: ui-monospace, "Cascadia Code", "SF Mono", Consolas, "Liberation Mono", monospace;
  --fs-xs: 12px; --fs-sm: 13px; --fs-base: 14px; --fs-md: 15px;
  --fs-lg: 17px; --fs-xl: 20px; --fs-2xl: 25px;

  /* geometry */
  --r-1: 6px; --r-2: 9px; --r-3: 13px; --r-pill: 999px;
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px; --sp-6: 32px; --sp-7: 48px;
  --maxw: 1080px;
  --shadow-1: 0 1px 2px rgba(0,0,0,.4);
  --shadow-2: 0 8px 28px -8px rgba(0,0,0,.6);
  --ease: cubic-bezier(.22, 1, .36, 1);
  --dur: 170ms;

  /* z-index scale */
  --z-nav: 100; --z-sticky: 200; --z-backdrop: 300; --z-modal: 400; --z-toast: 500; --z-tooltip: 600;

  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: var(--fs-base);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
[hidden] { display: none !important; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
input, select, textarea { font: inherit; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; border-radius: var(--r-1); }
svg { flex: none; }
.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.tnum { font-variant-numeric: tabular-nums; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ── App shell ─────────────────────────────────────────── */
.app { display: flex; flex-direction: column; min-height: 100dvh; overflow-x: clip; }

.topbar {
  position: sticky; top: 0; z-index: var(--z-nav);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.topbar-inner {
  max-width: var(--maxw); margin: 0 auto;
  display: flex; align-items: center; gap: var(--sp-4);
  padding: 10px max(16px, calc((100% - var(--maxw)) / 2 + 16px));
}
.brand { display: flex; align-items: center; gap: 9px; font-weight: 700; font-size: var(--fs-md); letter-spacing: -.01em; }
.brand .mark { width: 26px; height: 26px; display: grid; place-items: center; color: var(--ok); }
.brand .mark img { width: 100%; height: 100%; object-fit: contain; display: block; }
.brand small { color: var(--muted); font-weight: 500; font-size: var(--fs-xs); }
.spacer { flex: 1; }

.farm-switch { width: auto; max-width: 220px; margin-left: 14px; padding: 6px 30px 6px 10px; font-size: var(--fs-sm); }
.usermenu { position: relative; }
.usermenu-btn {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 8px 5px 6px; border-radius: var(--r-2);
  border: 1px solid var(--border); background: var(--surface-2);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.usermenu-btn:hover { border-color: var(--border-strong); }
.avatar {
  width: 24px; height: 24px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--accent); color: #fff; font-weight: 700; font-size: var(--fs-xs);
}
.usermenu-btn .who { max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-sm); }
.menu-pop {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: var(--z-modal);
  min-width: 220px; padding: 6px;
  background: var(--surface-2); border: 1px solid var(--border-strong);
  border-radius: var(--r-2); box-shadow: var(--shadow-2);
  animation: pop var(--dur) var(--ease);
}
@keyframes pop { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.menu-pop .head { padding: 8px 10px; border-bottom: 1px solid var(--border); margin-bottom: 4px; }
.menu-pop .head .n { font-weight: 600; }
.menu-pop .head .s { color: var(--muted); font-size: var(--fs-xs); font-family: var(--mono); }
.menu-pop button, .menu-pop a {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 9px 10px; border-radius: var(--r-1); color: var(--text); text-decoration: none;
  transition: background var(--dur) var(--ease);
}
.menu-pop button:hover, .menu-pop a:hover { background: var(--surface-3); }
.menu-pop button.danger { color: var(--crit); }
.menu-pop button svg, .menu-pop a svg { color: var(--muted); }
.menu-pop button.danger svg { color: var(--crit); }
/* Row "⋯" menu: same look as the account menu, but pinned to the viewport next to its button. */
.menu-pop.floating { position: fixed; right: auto; min-width: 200px; }
.menu-pop .menu-sep { height: 1px; background: var(--border); margin: 4px 2px; }
.menu-pop .menu-label { padding: 4px 10px 2px; font-size: var(--fs-xs); color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }

/* ── Nav tabs ──────────────────────────────────────────── */
.nav {
  position: sticky; top: 51px; z-index: calc(var(--z-nav) - 1);
  background: var(--bg); border-bottom: 1px solid var(--border);
}
.nav-inner {
  max-width: var(--maxw); margin: 0 auto;
  display: flex; gap: 2px; overflow-x: auto; scrollbar-width: none;
  padding: 0 max(16px, calc((100% - var(--maxw)) / 2 + 16px));
}
.nav-inner::-webkit-scrollbar { display: none; }
.nav a {
  display: flex; align-items: center; gap: 8px;
  padding: 12px 14px; color: var(--muted); font-weight: 600; font-size: var(--fs-sm);
  border-bottom: 2px solid transparent; white-space: nowrap;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.nav a:hover { color: var(--text); text-decoration: none; }
.nav a[aria-current="page"] { color: var(--text); border-bottom-color: var(--accent); }
.nav a svg { color: currentColor; }
.nav a .n { display: inline-flex; min-width: 18px; height: 18px; padding: 0 5px;
  align-items: center; justify-content: center; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--muted); font-size: 11px; font-weight: 700; }

/* ── Main ──────────────────────────────────────────────── */
main {
  flex: 1; width: 100%;
  max-width: var(--maxw); margin: 0 auto;
  padding: var(--sp-5) max(16px, calc((100% - var(--maxw)) / 2 + 16px)) var(--sp-7);
}
.page-head { display: flex; align-items: flex-end; gap: var(--sp-4); margin-bottom: var(--sp-4); flex-wrap: wrap; }
.page-head h1 { margin: 0; font-size: var(--fs-2xl); font-weight: 700; letter-spacing: -.02em; text-wrap: balance; }
.page-head .sub { color: var(--muted); font-size: var(--fs-sm); margin-top: 3px; }
.page-head .actions { margin-left: auto; display: flex; gap: var(--sp-2); align-items: center; }

.section-head {
  display: flex; align-items: center; gap: 10px;
  margin: var(--sp-5) 0 var(--sp-3);
}
.section-head:first-of-type { margin-top: var(--sp-2); }
.section-head h2 { margin: 0; font-size: var(--fs-sm); font-weight: 700; color: var(--muted); letter-spacing: .01em; }
.section-head .rule { flex: 1; height: 1px; background: var(--border); }
.section-head .count { font-size: var(--fs-xs); color: var(--faint); font-weight: 600; font-variant-numeric: tabular-nums; }

/* ── Buttons ───────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px 13px; border-radius: var(--r-2);
  border: 1px solid var(--border-strong); background: var(--surface-2); color: var(--text);
  font-weight: 600; font-size: var(--fs-sm);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.btn:hover { background: var(--surface-3); border-color: var(--border-strong); }
.btn:active { transform: translateY(1px); }
.btn svg { width: 16px; height: 16px; }
.btn-primary { background: var(--accent); border-color: transparent; color: #fff; }
.btn-primary:hover { background: var(--accent-hover); }
.btn-primary:active { background: var(--accent-press); }
.btn-ghost { background: transparent; border-color: var(--border); }
.btn-ghost:hover { background: var(--surface-2); }
.btn-danger { background: transparent; border-color: color-mix(in srgb, var(--crit) 55%, var(--border)); color: var(--crit); }
.btn-danger:hover { background: var(--crit-soft); }
.btn-sm { padding: 5px 9px; font-size: var(--fs-xs); border-radius: var(--r-1); }
.btn:disabled { opacity: .45; cursor: not-allowed; transform: none; }
.btn.is-loading { color: transparent; position: relative; pointer-events: none; }
.btn.is-loading::after {
  content: ""; position: absolute; width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,.35); border-top-color: #fff; animation: spin .7s linear infinite;
}
.btn-ghost.is-loading::after, .btn.is-loading:not(.btn-primary)::after { border-color: var(--border-strong); border-top-color: var(--text); }
@keyframes spin { to { transform: rotate(360deg); } }

.icon-btn {
  width: 32px; height: 32px; border-radius: var(--r-2); flex: none;
  display: grid; place-items: center;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--muted);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.icon-btn:hover { color: var(--text); border-color: var(--border-strong); }
.icon-btn svg { width: 16px; height: 16px; }
.icon-btn:disabled { opacity: .35; cursor: default; pointer-events: none; }

/* ── Inputs ────────────────────────────────────────────── */
.field { display: flex; flex-direction: column; gap: 6px; }
.field > label { font-size: var(--fs-sm); font-weight: 600; }
.field .opt { color: var(--faint); font-weight: 400; }
.field .hint { font-size: var(--fs-xs); color: var(--muted); line-height: 1.45; }
.field .err { font-size: var(--fs-xs); color: var(--crit); font-weight: 600; }
.input, .select {
  width: 100%; padding: 9px 11px;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--r-2);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), background var(--dur) var(--ease);
}
.input::placeholder { color: var(--muted); }
.input:hover, .select:hover { border-color: var(--faint); }
.input:focus, .select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--ring); background: var(--surface); }
.input:disabled, .select:disabled { opacity: .5; cursor: not-allowed; }
.field.invalid .input, .field.invalid .select { border-color: var(--crit); }
.select { appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%239aa4b2' stroke-width='2.5' stroke-linecap='round'><path d='m4 6 4 4 4-4'/></svg>");
  background-repeat: no-repeat; background-position: right 10px center; padding-right: 32px; }
.input-suffix { position: relative; display: flex; align-items: center; }
.input-suffix .input { padding-right: 46px; }
.input-suffix .sfx { position: absolute; right: 11px; color: var(--muted); font-size: var(--fs-sm); pointer-events: none; }
.input-row { display: flex; gap: var(--sp-3); }
.input-row > * { flex: 1; }

/* segmented control */
.seg { display: inline-flex; padding: 3px; gap: 3px; background: var(--bg); border: 1px solid var(--border-strong); border-radius: var(--r-2); }
.seg button {
  padding: 7px 13px; border-radius: var(--r-1); color: var(--muted); font-weight: 600; font-size: var(--fs-sm);
  display: inline-flex; align-items: center; gap: 6px;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.seg button svg { width: 15px; height: 15px; }
.seg button:hover { color: var(--text); }
.seg button[aria-pressed="true"] { background: var(--surface-3); color: var(--text); box-shadow: var(--shadow-1); }
/* Compact variant — the day-range toggle on a dashboard water-level card (see dayRangeSeg) sits
   inside a .dev-card alongside .btn-sm controls, so it matches that sizing instead of the roomier
   default (built for standalone form fields). */
.seg.sm { padding: 2px; gap: 2px; }
.seg.sm button { padding: 5px 9px; font-size: var(--fs-xs); }

/* toggle */
.toggle { position: relative; width: 42px; height: 24px; flex: none; display: inline-block; overflow: hidden; border-radius: var(--r-pill); }
.toggle input { position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%; margin: 0; padding: 0; border: 0; cursor: pointer; }
.toggle .track { position: absolute; inset: 0; border-radius: var(--r-pill); background: var(--border-strong); transition: background var(--dur) var(--ease); }
.toggle .knob { position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%; background: #fff;
  transition: transform 200ms var(--ease); box-shadow: 0 1px 2px rgba(0,0,0,.5); }
.toggle input:checked + .track { background: var(--ok); }
.toggle input:checked + .track + .knob { transform: translateX(18px); }
.toggle input:focus-visible + .track { box-shadow: 0 0 0 3px var(--ring); }
.toggle input:disabled { cursor: not-allowed; }
.toggle input:disabled + .track { opacity: .5; }

/* chips (multi-select) */
.chips { display: flex; flex-wrap: wrap; gap: 7px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 10px; border-radius: var(--r-pill); font-size: var(--fs-xs); font-weight: 600;
  border: 1px solid var(--border-strong); background: var(--surface-2); color: var(--muted);
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.chip:hover { color: var(--text); border-color: var(--faint); }
.chip[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.chip svg { width: 13px; height: 13px; }
.chip .kind { opacity: .7; font-weight: 500; }

/* ── Badges ────────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 8px; border-radius: var(--r-pill);
  font-size: var(--fs-xs); font-weight: 700; white-space: nowrap;
}
.badge .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.badge svg { width: 12px; height: 12px; }
.badge.ok   { color: var(--ok);   background: var(--ok-soft); }
.badge.warn { color: var(--warn); background: var(--warn-soft); }
.badge.crit { color: var(--crit); background: var(--crit-soft); }
.badge.off  { color: var(--muted); background: var(--off-soft); }
.badge.on   { color: var(--ok); background: var(--ok-soft); }
.badge.on .dot { box-shadow: 0 0 6px var(--ok); }
.badge.neutral { color: var(--muted); background: var(--surface-2); border: 1px solid var(--border); }
.badge.accent { color: var(--accent); background: var(--accent-soft); }

/* ── Cards ─────────────────────────────────────────────── */
.grid {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fill, minmax(258px, 1fr));
}
.card {
  border: 1px solid var(--border); border-radius: var(--r-3); background: var(--surface);
  padding: var(--sp-4);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease), background var(--dur) var(--ease);
}
.card.link { cursor: pointer; }
.card.link:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.card.warn { border-color: color-mix(in srgb, var(--warn) 45%, var(--border)); background: color-mix(in srgb, var(--warn-soft) 45%, var(--surface)); }
.card.crit { border-color: color-mix(in srgb, var(--crit) 45%, var(--border)); background: color-mix(in srgb, var(--crit-soft) 45%, var(--surface)); }

.dev-card .top { display: flex; align-items: flex-start; gap: 10px; }
.dev-card .ic {
  width: 34px; height: 34px; border-radius: var(--r-2); flex: none;
  display: grid; place-items: center; background: var(--surface-2); color: var(--muted);
}
.dev-card .ic svg { width: 18px; height: 18px; }
.dev-card .ic.water { background: rgba(57,211,245,.12); color: var(--info); }
.dev-card .ic.accent { background: var(--accent-soft); color: var(--accent); }
.dev-card .ic.ok { background: var(--ok-soft); color: var(--ok); }
.dev-card .nm { font-weight: 600; font-size: var(--fs-sm); line-height: 1.35; overflow-wrap: anywhere; }
.dev-card .top .badge { margin-left: auto; }
.dev-card .value { display: flex; align-items: baseline; gap: 4px; margin: 12px 0 2px; }
.dev-card .value .big { font-size: var(--fs-2xl); font-weight: 700; letter-spacing: -.02em; font-family: var(--mono); }
.dev-card .value .unit { font-size: var(--fs-sm); color: var(--muted); font-weight: 600; }
.dev-card .range { font-size: var(--fs-xs); color: var(--muted); }
.dev-card .state-lg { font-size: var(--fs-lg); font-weight: 700; margin: 10px 0 2px; letter-spacing: -.01em; }
.dev-card .state-lg.on  { color: var(--ok); }
.dev-card .state-lg.off { color: var(--muted); }
.dev-card .spark, .dev-card .timeline { width: 100%; height: 150px; margin-top: 10px; display: block; }
.dev-card .timeline { height: 12px; border-radius: 3px; overflow: hidden; }
.dev-card .foot {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--border);
  font-size: var(--fs-xs); color: var(--muted);
}
.dev-card .foot .sep { width: 3px; height: 3px; border-radius: 50%; background: var(--faint); }
/* generic device fields (outside irrigation_*) — a plain label/value or label/control row, several
   stacked per card, since a device type can carry any number of arbitrary fields. */
.gf-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 7px 0; border-top: 1px solid var(--border); }
.dev-card .top + .gf-row { border-top: none; margin-top: 10px; }
.dev-card .last-active + .gf-row { border-top: none; margin-top: 10px; }
/* Why the badge says what it says: when the device last reported, and (if silent) for how long. */
.dev-card .last-active { margin-top: 8px; font-size: var(--fs-xs); color: var(--muted); line-height: 1.45; }
.dev-card .last-active.off { color: var(--warn); }
/* Field picker with its direct/invert choice beside it; stacks on a phone when the two don't fit. */
.map-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.map-row .select { flex: 1 1 200px; min-width: 0; width: auto; }
.gf-k { font-size: var(--fs-xs); color: var(--muted); }
/* Field name on a device card is a button that opens that field's history. */
.gf-link { display: inline-flex; align-items: center; gap: 5px; padding: 2px 0; font-size: var(--fs-xs); color: var(--muted); text-align: left;
  border-bottom: 1px dashed transparent; transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.gf-link svg { width: 13px; height: 13px; opacity: .55; flex: none; }
.gf-link:hover, .gf-link:focus-visible { color: var(--text); border-bottom-color: var(--faint); }
.gf-link:hover svg, .gf-link:focus-visible svg { opacity: 1; color: var(--accent); }
.gf-v { font-size: var(--fs-sm); font-weight: 600; font-family: var(--mono); }
.input-sm { padding: 5px 8px; font-size: var(--fs-xs); }
.dev-card .foot .test { margin-left: auto; }

/* ── แดชบอร์ด edit mode — current-widgets list (see dashboardEditPanel) ── */
.widget-list { display: flex; flex-direction: column; gap: 1px; border: 1px solid var(--border); border-radius: var(--r-3); overflow: hidden; margin-bottom: var(--sp-4); }
.widget-row { display: flex; align-items: center; gap: var(--sp-3); padding: 10px var(--sp-4); background: var(--surface); }
/* min-width:0 overrides the flex-item default of min-width:auto, which otherwise sizes a flex child to
   its content's intrinsic width no matter how little room is actually available — harmless for the
   short text every other .widget-row puts in .grow, but a nowrap-truncated URL's intrinsic width is
   the full unwrapped string, so without this it pushed the row (and the whole page) wider than the
   viewport instead of actually truncating inside it. */
.widget-row .grow { flex: 1; min-width: 0; font-size: var(--fs-sm); font-weight: 600; overflow-wrap: anywhere; }
.widget-row .sub { display: block; font-size: var(--fs-xs); font-weight: 400; color: var(--muted); margin-top: 1px; }
.widget-row.is-hidden > svg, .widget-row.is-hidden > .grow { opacity: 0.55; }
/* Buttons wrap as one group: on a phone the title keeps a readable width and the buttons drop below it. */
.widget-row .row-actions { display: flex; gap: var(--sp-2); margin-left: auto; flex: none; }
@media (max-width: 520px) {
  .widget-row { flex-wrap: wrap; }
  .widget-row .grow { flex: 1 1 140px; }
}

/* ── Task cards ────────────────────────────────────────── */
.tasks { display: flex; flex-direction: column; gap: var(--sp-3); }
.task {
  border: 1px solid var(--border); border-radius: var(--r-3); background: var(--surface);
  padding: var(--sp-4) var(--sp-4) 12px;
  transition: border-color var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.task.is-off { opacity: .58; }
.task .row1 { display: flex; align-items: flex-start; gap: var(--sp-3); }
.task .sentence { flex: 1; font-size: var(--fs-md); line-height: 1.7; }
.task .sentence b { font-weight: 700; }
.tk {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: var(--r-1); font-size: var(--fs-xs); font-weight: 700;
  vertical-align: baseline;
}
.tk svg { width: 13px; height: 13px; }
.tk.when { color: var(--warn); background: var(--warn-soft); }
.tk.then { color: var(--accent); background: var(--accent-soft); }
.tk.every { color: var(--info); background: rgba(57,211,245,.12); }
.task .meta {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 11px; padding-top: 10px; border-top: 1px solid var(--border);
  font-size: var(--fs-xs); color: var(--muted);
}
.task .meta .sep { width: 3px; height: 3px; border-radius: 50%; background: var(--faint); }
.task .meta .acts { margin-left: auto; display: flex; gap: 4px; }

/* filter chips row */
.filters { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: var(--sp-4); }
.filters button {
  padding: 6px 12px; border-radius: var(--r-pill); font-size: var(--fs-xs); font-weight: 600;
  border: 1px solid var(--border); background: var(--surface); color: var(--muted);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.filters button:hover { color: var(--text); }
.filters button[aria-pressed="true"] { color: var(--text); border-color: var(--border-strong); background: var(--surface-2); }

/* ── Inline form panel (create / edit task) ────────────── */
.form-panel {
  border: 1px solid var(--accent); border-radius: var(--r-3);
  background: var(--surface); box-shadow: 0 0 0 3px var(--accent-soft);
  padding: var(--sp-5); margin-bottom: var(--sp-4);
  animation: reveal var(--dur) var(--ease);
}
@keyframes reveal { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
.form-panel h3 { margin: 0 0 var(--sp-4); font-size: var(--fs-lg); font-weight: 700; letter-spacing: -.01em; }
.form-grid { display: flex; flex-direction: column; gap: var(--sp-4); }
.preview {
  border: 1px dashed var(--border-strong); border-radius: var(--r-2);
  background: var(--bg); padding: 12px var(--sp-4);
  font-size: var(--fs-md); line-height: 1.7;
}
.preview .lbl { display: block; font-size: var(--fs-xs); color: var(--muted); font-weight: 600; margin-bottom: 5px; }
.form-panel .foot { display: flex; gap: var(--sp-2); justify-content: flex-end; margin-top: var(--sp-2); }
.form-panel .foot .spacer { flex: 1; }

/* ── Settings ──────────────────────────────────────────── */
.settings { display: flex; flex-direction: column; gap: var(--sp-4); max-width: 620px; }
.panel { border: 1px solid var(--border); border-radius: var(--r-3); background: var(--surface); }
.panel > header {
  display: flex; align-items: center; gap: 10px;
  padding: 14px var(--sp-4); border-bottom: 1px solid var(--border);
}
.panel > header h2 { margin: 0; font-size: var(--fs-md); font-weight: 700; }
.panel > header .desc { font-size: var(--fs-xs); color: var(--muted); }
.panel .body { padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-4); }
.panel .body.rows { gap: 0; padding: 4px var(--sp-4); }
.kv { display: flex; align-items: center; gap: var(--sp-3); padding: 12px 0; border-bottom: 1px solid var(--border); font-size: var(--fs-sm); }
.kv:last-child { border-bottom: none; }
.kv .k { color: var(--muted); flex: 1; min-width: 0; }
.kv .v { flex: none; margin-left: auto; font-weight: 600; text-align: right; display: inline-flex; align-items: center; gap: 8px; justify-content: flex-end; }
.panel .body .save-row { display: flex; align-items: center; gap: var(--sp-3); }
.panel .body .save-row .status { font-size: var(--fs-xs); color: var(--ok); font-weight: 600; }

.pw-meter { display: flex; gap: 4px; margin-top: 6px; }
.pw-meter span { flex: 1; height: 3px; border-radius: var(--r-pill); background: var(--border-strong); transition: background var(--dur) var(--ease); }
.pw-meter[data-s="1"] span:nth-child(1) { background: var(--crit); }
.pw-meter[data-s="2"] span:nth-child(-n+2) { background: var(--warn); }
.pw-meter[data-s="3"] span:nth-child(-n+3) { background: var(--info); }
.pw-meter[data-s="4"] span { background: var(--ok); }

/* ── Empty / skeleton / error ──────────────────────────── */
.empty {
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--sp-3);
  padding: var(--sp-7) var(--sp-4); border: 1px dashed var(--border); border-radius: var(--r-3);
  background: var(--surface);
}
.empty .ic { width: 44px; height: 44px; border-radius: var(--r-2); display: grid; place-items: center;
  background: var(--surface-2); color: var(--faint); }
.empty h3 { margin: 0; font-size: var(--fs-md); font-weight: 700; }
.empty p { margin: 0; color: var(--muted); font-size: var(--fs-sm); max-width: 42ch; }
.empty .example {
  margin-top: 4px; font-size: var(--fs-sm); color: var(--muted);
  border: 1px dashed var(--border-strong); border-radius: var(--r-2); padding: 10px 14px; background: var(--bg);
}

.skeleton { position: relative; overflow: hidden; background: var(--surface-2); border-radius: var(--r-1); }
.skeleton::after {
  content: ""; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.05), transparent);
  animation: shimmer 1.3s infinite;
}
@keyframes shimmer { to { transform: translateX(100%); } }
.sk-card { height: 158px; border-radius: var(--r-3); }
.sk-line { height: 12px; margin: 8px 0; }

.error-box {
  border: 1px solid color-mix(in srgb, var(--crit) 45%, var(--border));
  background: var(--crit-soft); border-radius: var(--r-3);
  padding: var(--sp-4); display: flex; gap: var(--sp-3); align-items: flex-start;
}
.error-box svg { color: var(--crit); flex: none; }
.error-box .t { font-weight: 700; }
.error-box .s { font-size: var(--fs-sm); color: var(--muted); margin-top: 2px; }

/* ── Login ─────────────────────────────────────────────── */
/* min-height is a floor, not an addition — padding-bottom alone here would just get absorbed inside
   a 100dvh box (place-items:center would simply give the card less centered room within it) unless
   content+padding together already exceeded one viewport, so it produced close to zero real overflow
   in practice. Setting min-height itself to well over one viewport is what actually guarantees
   scrollable page overflow exists for as long as this screen is shown (app.js's setLoginMode(true)
   lifts html/body's usual height:100% cap so this can extend the page instead of being capped by
   box-sizing:border-box) — not just a reaction conjured on focus. Several in-app WebViews (Messenger,
   Line) never resize the viewport for the on-screen keyboard and don't reliably report it through any
   JS-visible channel either, so without guaranteed overflow a focused field behind the keyboard had
   nowhere for even the browser's own baseline scroll-into-view behavior to go. See app.js's
   boot()/renderLogin/renderJoinConfirm. */
.login-wrap { min-height: calc(100dvh + 50vh); display: grid; place-items: start center; padding: var(--sp-4); padding-top: max(var(--sp-6), 8vh); }
.login-card { width: 100%; max-width: 380px; border: 1px solid var(--border); border-radius: var(--r-3);
  background: var(--surface); padding: var(--sp-6); }
/* logo.png is transparent with light lettering, so it sits straight on the card (no tile). */
.login-logo { display: block; width: 160px; height: 160px; margin: 0 auto var(--sp-2); object-fit: contain; }
.login-card .tag { text-align: center; color: var(--muted); font-size: var(--fs-sm); margin-bottom: var(--sp-5); }
.login-card .form-grid { gap: var(--sp-3); }
.login-card .devhint { text-align: center; font-size: var(--fs-xs); color: var(--faint); margin-top: var(--sp-4); }
.login-card .devhint code { font-family: var(--mono); color: var(--muted); }
.login-card .switch-mode { text-align: center; font-size: var(--fs-sm); color: var(--muted); margin-top: var(--sp-4); }
.login-card .switch-mode a { font-weight: 600; }

/* ── Confirm dialog ────────────────────────────────────── */
dialog.confirm {
  border: 1px solid var(--border-strong); border-radius: var(--r-3);
  background: var(--surface); color: var(--text); padding: 0; max-width: 380px; width: calc(100% - 32px);
  box-shadow: var(--shadow-2);
}
dialog.confirm::backdrop { background: rgba(0,0,0,.55); }
dialog.confirm .body { padding: var(--sp-5); }
dialog.confirm h3 { margin: 0 0 8px; font-size: var(--fs-md); font-weight: 700; }
dialog.confirm p { margin: 0; color: var(--muted); font-size: var(--fs-sm); }
dialog.confirm .foot { display: flex; gap: var(--sp-2); justify-content: flex-end; padding: 12px var(--sp-5) var(--sp-5); }
/* ── ค่าล่าสุด dialog — wider variant of .confirm, adds a scrollable table (see latestValuesDialog) ── */
dialog.confirm.detail { max-width: 480px; }
dialog.confirm.detail .body p { margin-top: 4px; }
.lv-table-host { padding: 0 var(--sp-5); max-height: 50vh; overflow-y: auto; }
.lv-table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.lv-table th { text-align: left; font-size: var(--fs-xs); color: var(--muted); font-weight: 600; padding: 6px 8px; border-bottom: 1px solid var(--border); }
.lv-table td { padding: 7px 8px; border-bottom: 1px solid var(--border); font-family: var(--mono); }
.lv-table tr:last-child td { border-bottom: none; }

/* Per-field history dialog */
dialog.confirm.detail.history { width: min(580px, 94vw); max-width: none; }
/* Only the middle scrolls; the title/range switcher and the Close button stay put. `[open]` because a
   plain display:flex on <dialog> would override its closed (display:none) state. */
dialog.confirm.detail.history[open] { display: flex; flex-direction: column; overflow: hidden; }
.fh-content { padding: var(--sp-4) var(--sp-5) 0; flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.fh-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: var(--sp-2); }
.fh-tile { padding: 10px 12px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-2); }
.fh-tile .k { font-size: var(--fs-xs); color: var(--muted); }
.fh-tile .v { margin-top: 2px; font-size: var(--fs-md); font-weight: 700; font-family: var(--mono); letter-spacing: -.01em; overflow-wrap: anywhere; }
.fh-tile .s { margin-top: 1px; font-size: var(--fs-xs); color: var(--faint); }
.fh-chart { margin-top: var(--sp-3); }
.fh-chart .spark { width: 100%; height: 150px; display: block; }
.fh-chart .fh-bar { width: 100%; height: 28px; display: block; border-radius: 4px; overflow: hidden; }
.fh-legend { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: 8px; font-size: var(--fs-xs); color: var(--muted); }
.fh-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 5px; vertical-align: -1px; }
.fh-note { margin-top: 8px !important; font-size: var(--fs-xs) !important; color: var(--faint) !important; }
.fh-empty { padding: var(--sp-4) 0; text-align: center; color: var(--muted); font-size: var(--fs-sm); }
.fh-list { margin-top: var(--sp-4); }
.fh-list-h { font-size: var(--fs-xs); font-weight: 600; color: var(--muted); margin-bottom: 4px; }
.fh-row { display: flex; justify-content: space-between; gap: var(--sp-3); padding: 7px 0; border-top: 1px solid var(--border); font-size: var(--fs-xs); }
.fh-row .d { color: var(--muted); font-family: var(--mono); white-space: nowrap; }
.fh-row .val { font-family: var(--mono); font-weight: 600; overflow-wrap: anywhere; }

/* ── Toast ─────────────────────────────────────────────── */
#toast {
  position: fixed; right: 16px; bottom: 16px; z-index: var(--z-toast);
  display: flex; flex-direction: column; gap: 8px; max-width: 340px;
}
#toast .t {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 14px; border-radius: var(--r-2);
  background: var(--surface-2); border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-2); font-size: var(--fs-sm); font-weight: 600;
  animation: toast-in 220ms var(--ease);
}
#toast .t.ok  { border-color: color-mix(in srgb, var(--ok) 45%, var(--border-strong)); }
#toast .t.err { border-color: color-mix(in srgb, var(--crit) 45%, var(--border-strong)); }
#toast .t.ok svg  { color: var(--ok); }
#toast .t.err svg { color: var(--crit); }
#toast .t.leaving { opacity: 0; transform: translateY(8px); transition: 240ms var(--ease); }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ── Responsive ────────────────────────────────────────── */
@media (max-width: 680px) {
  .topbar-inner, .nav-inner, main { padding-left: 14px; padding-right: 14px; }
  .brand small { display: none; }
  .usermenu-btn .who { display: none; }
  .page-head h1 { font-size: var(--fs-xl); }
  .grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 460px) {
  .grid { grid-template-columns: 1fr; }
  .input-row { flex-direction: column; }
  .nav { top: 51px; }
}

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