/* ── Reset & variables ─────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --primary: #1d6f42;
  --primary-dark: #155234;
  --primary-light: #d1fae5;
  --bg: #f1f5f9;
  --card: #ffffff;
  --text: #1e293b;
  --muted: #64748b;
  --border: #e2e8f0;
  --danger: #dc2626;
  --danger-bg: #fef2f2;
  --success: #16a34a;
  --warning: #92400e;
  --warning-bg: #fef3c7;
  --radius: 12px;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans Thai', sans-serif;
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  font-size: 16px;
  line-height: 1.5;
}

/* ── Layout ────────────────────────────────────────────────────────────────── */
.page {
  max-width: 480px;
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.page-header {
  background: var(--primary);
  color: var(--on-brand);
  padding: 1rem 1.25rem 1rem;
  position: sticky;
  top: 0;
  z-index: 10;
}

.page-header h1 {
  font-size: 1.1rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.header-logo { flex-shrink: 0; }   /* size + plate: one-platform.css */

.page-header .subtitle {
  font-size: 0.85rem;
  opacity: 0.85;
  margin-top: 0.15rem;
}

/* ── Portal header row (base_portal.html) — additive only, .page-header
   itself stays untouched since claim_form.html/success.html/error.html
   rely on it stacking h1+subtitle vertically. ────────────────────────────── */
.page-header-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
}

.page-content {
  flex: 1;
  padding: 1rem 1rem 2rem;
}

/* ── Card / sections ───────────────────────────────────────────────────────── */
.card {
  background: var(--card);
  border-radius: var(--radius);
  padding: 1.25rem;
  box-shadow: 0 1px 3px rgba(0,0,0,.08);
}

.section {
  margin-bottom: 1rem;
}

.section-title {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 1rem;
}

/* ── Login page ────────────────────────────────────────────────────────────── */
.login-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 1.5rem;
  background: var(--bg);
}

.login-logo {
  margin-bottom: 0.75rem;
}

.login-logo-img {
  width: 90px;
  height: 90px;
  object-fit: contain;
  border-radius: 50%;
  background: white;
  padding: 8px;
  box-shadow: 0 2px 12px rgba(0,0,0,0.12);
}

.login-title {
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 0.25rem;
  text-align: center;
}

.login-sub {
  color: var(--muted);
  font-size: 0.9rem;
  margin-bottom: 1.75rem;
  text-align: center;
}

.login-card {
  width: 100%;
  max-width: 360px;
  background: var(--card);
  border-radius: var(--radius);
  padding: 1.75rem 1.5rem;
  box-shadow: 0 4px 20px rgba(0,0,0,.1);
}

/* ── Form elements ─────────────────────────────────────────────────────────── */
.field {
  margin-bottom: 1rem;
}

.field:last-child {
  margin-bottom: 0;
}

.field label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 0.4rem;
}

.field select,
.field input[type="text"],
.field input[type="search"],
.field input[type="month"],
.field input[type="password"],
.field input[type="date"],
.field textarea {
  width: 100%;
  padding: 0 0.8rem;
  font-size: 0.95rem;
  border: 2px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  appearance: auto;
  -webkit-appearance: auto;
  font-family: inherit;
}

.field textarea {
  resize: vertical;
  padding: 0.6rem 0.8rem;
}
/* A field written as <label class="field"><span>name</span><control></label> (the supplier portal, บัญชี
   Supplier's rule form): the name above the box, like <div class="field"><label>…</label> (2026-10-09 — a
   label is inline, so the name, the box and the next field ran along one line). */
label.field { display: flex; flex-direction: column; gap: 0.4rem; }
label.field > span:first-child { font-size: 0.85rem; font-weight: 600; color: var(--ink); }
/* One box height for a form field (2026-10-09, the user: "these forms look bigger than other boxes on other
   pages"): --size-tap, 0.95rem — the Approval page's size. It was 0.75rem 1rem padding at 1rem, ~60px, while
   the rest of the app drew 40-44px. Filter rows keep their own --size-control-sm (.form-inline below). */
.field :where(select, input[type="text"], input[type="search"], input[type="month"], input[type="password"], input[type="date"]) {   /* :where = no weight: a filter row or a table cell rule still wins */
  height: var(--size-tap);
}

/* The two dropdowns that stand in for <input type="month"> where the browser has no month picker
   (desktop Firefox, desktop Safari) — built by static/list-tools.js. Side by side, in the room the
   picker would take, styled as the form's other dropdowns by the rule above. */
.month-fallback { display: flex; gap: 6px; }
.field .month-fallback select { width: auto; flex: 1 1 auto; min-width: 0; }
.field .month-fallback select + select { flex: 0 1 auto; }

.field input[type="file"] {
  width: 100%;
  padding: 0.6rem;
  font-size: 0.85rem;
  border: 2px dashed var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--muted);
}

.field select:focus,
.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--primary);
  background: var(--surface);
}

.field select:disabled {
  opacity: 0.6;
}

/* ── Buttons ───────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.85rem 1.5rem;
  border-radius: 10px;
  border: none;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
  text-decoration: none;
  transition: opacity 0.15s, transform 0.1s;
}

.btn:active { transform: scale(0.97); }
.btn:disabled { opacity: 0.6; cursor: not-allowed; }

.btn-primary {
  background: var(--primary);
  color: var(--on-brand);
  width: 100%;
}

.btn-primary:hover { background: var(--primary-dark); }

.btn-outline {
  background: transparent;
  color: var(--brand-text);
  border: 2px solid var(--primary);
}

.btn-success {
  background: var(--success-solid);
  color: var(--on-brand);
  width: 100%;
}

/* ── Alerts ────────────────────────────────────────────────────────────────── */
.alert {
  padding: 0.75rem 1rem;
  border-radius: 8px;
  font-size: 0.9rem;
  margin-bottom: 1rem;
}

.alert-danger {
  background: var(--danger-bg);
  color: var(--danger);
  border: 1px solid var(--danger);
}

.alert-success {
  background: var(--primary-light);
  color: var(--success);
  border: 1px solid var(--success);
}

/* ── Internal remarks (case notes) — identical across qc/purchasing/admin
   claim detail pages, so this lives in the shared stylesheet rather than
   being duplicated per portal.css. ────────────────────────────────────────── */
.remark-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.remark-item {
  background: var(--bg);
  border-radius: 8px;
  padding: 0.75rem 1rem;
}

.remark-meta {
  font-size: 0.8rem;
  color: var(--muted);
  margin-bottom: 0.35rem;
}

.remark-text {
  font-size: 0.95rem;
  white-space: pre-wrap;
  word-break: break-word;
}

.remark-empty {
  color: var(--muted);
  text-align: center;
  padding: 1rem 0;
  font-size: 0.9rem;
  margin-bottom: 1rem;
}

.remark-form textarea {
  width: 100%;
  padding: 0.75rem 1rem;
  font-size: 0.95rem;
  border: 2px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-family: inherit;
  resize: vertical;
  margin-bottom: 0.6rem;
}

.remark-form textarea:focus {
  outline: none;
  border-color: var(--primary);
  background: var(--surface);
}

/* ===== purchasing workload additions ===== */
/* (The horizontal pill nav that lived here became the sidebar in static/shell.css, 2026-09-27.) */

.wl-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.wl-table th, .wl-table td { padding: 8px 10px; border-bottom: 1px solid var(--border); text-align: left; vertical-align: top; }
.wl-table th { background: var(--surface-sunken); font-weight: 600; white-space: nowrap; }
.wl-table-wrap { overflow-x: auto; }
.wl-row-overdue { background: var(--danger-surface); }
.wl-row-ready { background: var(--success-surface); }

.badge { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: 0.78rem; white-space: nowrap; }
.badge-triage { background: var(--warning-surface); color: var(--pill-warning); }
.badge-active { background: var(--info-surface); color: var(--pill-info); }
.badge-ready { background: var(--success-surface); color: var(--pill-success); }
.badge-closed { background: var(--track); color: var(--ink-muted); }
.badge-cancelled { background: var(--danger-surface); color: var(--pill-danger); }
.badge-set_aside { background: var(--surface-sunken); color: var(--ink-muted); }
.badge-age-warn { background: var(--warning-surface); color: var(--pill-warning); }
.badge-age-late { background: var(--danger-surface); color: var(--pill-danger); font-weight: 700; }
.badge-leave { background: var(--danger-surface); color: var(--pill-danger); }
.badge-ok { background: var(--success-surface); color: var(--pill-success); }

.board-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
.board-col { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; }
.board-col-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; gap: 6px; }
.board-col-header .name { font-weight: 700; }
.score-pill { background: var(--primary, var(--brand-600)); color: var(--on-brand); border-radius: 999px; padding: 2px 10px; font-size: 0.8rem; }
.case-card { display: block; border: 1px solid var(--border); border-radius: 10px; padding: 8px 10px; margin-bottom: 8px; text-decoration: none; color: inherit; font-size: 0.85rem; background: var(--surface-sunken); }
.case-card:hover { border-color: var(--primary, var(--brand-600)); }
.case-card .doc { font-weight: 700; }
.case-card.overdue { background: var(--danger-surface); border-color: var(--danger); }
.case-card .meta { color: var(--ink-muted); font-size: 0.78rem; }

.inline-form { display: inline; }
.btn-danger { background: var(--danger-solid); color: var(--on-brand); }
.triage-banner { background: var(--warning-surface); border: 1px solid var(--warning-dot); border-radius: 10px; padding: 10px 14px; margin-bottom: 14px; }
.timeline { list-style: none; padding: 0; margin: 0; }
.timeline .t-meta { color: var(--ink-muted); font-size: 0.78rem; }
.detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; margin-bottom: 12px; }
.detail-grid .item .v { font-weight: 600; }
@media (max-width: 640px) { .board-grid { grid-template-columns: 1fr; } }

/* ===== approval dashboard additions (2026-08-30) ===== */
/* Lark status badges (synced ground truth) */
.badge-lk-pending { background: var(--warning-surface); color: var(--pill-warning); }
.badge-lk-approved { background: var(--success-surface); color: var(--pill-success); }
.badge-lk-rejected { background: var(--danger-surface); color: var(--pill-danger); }
.badge-lk-deleted, .badge-lk-other { background: var(--track); color: var(--ink-muted); }
/* Internal working-status badges */
.badge-wk-new { background: var(--warning-surface); color: var(--pill-warning); }
.badge-wk-received { background: var(--seasonal-surface); color: var(--seasonal); }
.badge-wk-in_progress { background: var(--info-surface); color: var(--pill-info); }
.badge-wk-waiting_info { background: var(--warning-surface); color: var(--pill-warning); }
.badge-wk-done { background: var(--success-surface); color: var(--pill-success); }
/* อนุมัติครบ — รอเปิด PO (2026-10-14): open, approved, the PO still to be opened — its own teal (the info family, edged and bold beside กำลังดำเนินการ) with a
   solid edge, so it reads neither as done (green) nor as waiting on someone else (amber / orange). The neutral
   default is :where(.badge) (no specificity), so a single class is enough here. */
.badge-wk-awaiting_po { background: var(--info-surface); color: var(--pill-info); border: 1px solid var(--info-dot); font-weight: 600; }
.badge-wk-other { background: var(--track); color: var(--ink-muted); }

.owner-checks label { display: flex; gap: 5px; align-items: center; font-size: 0.85rem; white-space: nowrap; cursor: pointer; }

.form-field-row { padding: 7px 0; border-bottom: 1px solid var(--border); }
.form-field-row:last-child { border-bottom: none; }
.form-field-row .k { color: var(--ink-muted); font-size: 0.78rem; }
.form-field-row .v { font-weight: 600; white-space: pre-wrap; word-break: break-word; }
.form-field-row .v code { font-weight: 400; font-size: 0.82rem; background: var(--surface-sunken); border-radius: 6px; padding: 2px 6px; word-break: break-all; }

/* ===== บันทึกการอนุมัติ (Lark) + open-in-Lark (2026-09-27) — approval_record.py ===== */
.lark-open { padding: 12px 16px; margin-top: 12px; }
.lark-open--mine { border: 1px solid var(--warning); background: var(--warning-surface); }
.lark-open__lead { font-weight: 700; color: var(--warning); margin-bottom: 8px; }
.lark-open__wait { font-weight: 500; }
.lark-open__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; }
.page-content .lark-open__go { padding: 10px 22px; font-size: 1rem; }
.lark-open__alt { font-size: 0.84rem; color: var(--brand-text); }
.lark-open__pending { font-size: 0.84rem; color: var(--ink); overflow-wrap: anywhere; }
.lark-open__hint { margin: 8px 0 0; }
/* อนุมัติ / ไม่อนุมัติ from the page (approval_decide) — green approve, red-outline reject */
.lark-decide { display: grid; gap: 8px; }
.lark-decide__label { font-size: 0.86rem; font-weight: 600; color: var(--warning); }
.lark-decide textarea { width: 100%; min-height: 3.2em; resize: vertical; font: inherit; padding: 8px 10px;
  border: 1px solid var(--warning); border-radius: 8px; background: var(--surface); box-sizing: border-box; }
.page-content .lark-decide__btn { width: auto; padding: 10px 24px; font-size: 1rem; border: 2px solid transparent; }
.page-content .lark-decide__btn--reject { color: var(--danger); border-color: var(--danger); background: var(--surface); }
.page-content .lark-decide__btn--reject:hover { background: var(--danger-bg); }
.lark-decide__btn[disabled] { opacity: 0.6; cursor: progress; }
.lark-open__sign { margin: 0 0 8px; padding: 8px 10px; border-radius: 8px; background: var(--danger-bg);
  color: var(--danger); font-weight: 600; font-size: 0.9rem; }
/* `.badge.x`, not `.x`: the app's generic `.badge` rule comes later in this file and would grey these out */
.badge.badge-await { background: var(--warning-surface); color: var(--pill-warning); font-weight: 700; }
.badge.apr-ok { background: var(--success-surface); color: var(--pill-success); }
.badge.apr-bad { background: var(--danger-surface); color: var(--pill-danger); }
.badge.apr-wait { background: var(--warning-surface); color: var(--pill-warning); }
.badge.apr-warn { background: var(--warning-surface); color: var(--pill-warning); }
.badge.apr-muted { background: var(--track); color: var(--ink-muted); }
.lark-mini { font-size: 0.74rem; font-weight: 600; color: var(--brand-text); white-space: nowrap; margin-left: 4px; }
.apr-record-card .footnote { margin: 8px 0 0; }
.wl-table.apr-record { min-width: 720px; }
.apr-record .apr-step { width: 150px; }
.apr-record .apr-result { width: 150px; }
.apr-record .apr-time { width: 130px; white-space: nowrap; }
.apr-step__name { display: block; font-weight: 600; }
.apr-en { display: block; color: var(--ink-muted); font-size: 0.72rem; }
.apr-mode { font-size: 0.76rem; color: var(--warning); margin-bottom: 2px; }
.apr-person { line-height: 1.55; }
.apr-name { font-weight: 600; }
.apr-mini { font-size: 0.7rem; padding: 1px 7px; }
.apr-note, .apr-by { font-size: 0.8rem; color: var(--ink); }
.apr-c + .apr-c { margin-top: 4px; }
.apr-comment { overflow-wrap: anywhere; }
.apr-waited { font-size: 0.78rem; font-weight: 600; color: var(--warning); white-space: normal; }
.apr-row.is-pending td { background: var(--warning-surface); }
.apr-row--end td { background: var(--surface-sunken); }
@media (max-width: 640px) {
  /* each step becomes a card: step + result on top, then who, what they wrote, when */
  .wl-table.apr-record, .apr-record tbody { display: block; min-width: 0; }
  .apr-record .apr-head { display: none; }
  .apr-record tr { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 4px 10px; background: var(--surface);
    border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; margin-bottom: 8px; }
  .apr-record td { display: block; border: 0; padding: 0; width: auto; background: none; }
  .apr-row.is-pending { background: var(--warning-surface); border-color: var(--warning); }
  .apr-row.is-pending td, .apr-row--end td { background: none; }
  .apr-record .apr-step { order: 1; flex: 1 1 0; min-width: 0; width: auto; }
  .apr-record .apr-step__name { display: inline; }
  .apr-record .apr-step .apr-en { display: inline; margin-left: 6px; }
  .apr-record .apr-result { order: 2; width: auto; }
  .apr-record .apr-people { order: 3; } .apr-record .apr-comment { order: 4; } .apr-record .apr-time { order: 5; }
  .apr-record .apr-people, .apr-record .apr-comment, .apr-record .apr-time { flex-basis: 100%; }
  .apr-record .apr-comment.is-empty { display: none; }
  .apr-record .apr-time { width: auto; color: var(--ink-muted); font-size: 0.8rem; }
  .apr-record-card .wl-table-wrap { overflow-x: visible; }
}

/* ===== desktop layout (2026-08-29): the base sheet is the claim webapp's 480px phone
   column — widen the shell on real screens; phone rendering unchanged ===== */
@media (min-width: 768px) {
  .page { max-width: 1360px; }
  .page-content { padding: 1.25rem 2rem 2.5rem; }
  .board-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
}

/* ===== UI refinement pass (2026-08-30) — append-only; base rules above are shared
   with sibling apps and stay untouched. Scoped to this app's own classes. ===== */

/* -- header: one-line brand, tidy user cluster, tighter on phone -- */
.header-brand { display: flex; align-items: center; gap: 12px; min-width: 0; }
.header-titles { min-width: 0; }
.page-header h1 { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 560px) {
  .page-header { padding: 0.7rem 1rem; }
  .page-header h1 { font-size: 0.98rem; }
  .page-header .subtitle { font-size: 0.72rem; }
}

/* -- section titles: consistent rhythm without per-template inline margins -- */
.page-content > .section-title { margin: 1.5rem 0 0.7rem; font-size: 1rem; }
.page-content > .section-title:first-child { margin-top: 0.35rem; }
.section-sub { font-weight: 400; color: var(--ink-muted); font-size: 0.8rem; }
@media (max-width: 640px) { span.section-sub { display: block; margin-top: 2px; } }

/* -- page toolbar (title + actions on one line) -- */
.page-toolbar {
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: 8px; margin: 0.35rem 0 0.75rem;
}
.page-toolbar .section-title { margin: 0; }
.inline-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* -- buttons: normalize; nothing full-width by default in this app -- */
.page-content .btn { width: auto; white-space: nowrap; }
.btn-sm { padding: 7px 14px; font-size: 0.84rem; border-radius: 8px; font-weight: 600; }
.btn-outline { background: var(--surface); }

/* -- tables: real horizontal scroll on phone instead of word-by-word squeeze -- */
.wl-table { min-width: 560px; }
.wl-table--wide { min-width: 800px; }
.wl-table--fit { min-width: 0; }
.wl-table th { color: var(--ink); font-size: 0.82rem; }
.wl-table td { line-height: 1.45; }
.td-doc { white-space: nowrap; }
.wl-table a { color: var(--brand-text); text-decoration: none; }
/* copy-the-request-number button (static/prq-phone.js): quiet, same line, never grows the row */
.ref-copy { display: inline-flex; align-items: center; justify-content: center; vertical-align: middle; width: 22px; height: 22px;
  margin: -4px 0 -4px 3px; padding: 0; border: 0; border-radius: 5px; background: transparent; color: var(--ink-muted); cursor: pointer; font: inherit; line-height: 1; }
.ref-copy:hover { background: var(--surface-hover); color: var(--brand-text); }
.ref-copy:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
.ref-copy.is-copied { color: var(--success); }
.ref-copy svg { display: block; pointer-events: none; }
.wl-table a:hover { text-decoration: underline; }
.row-inactive { opacity: 0.55; }
.empty-cell { color: var(--ink-subtle); text-align: center; padding: 1.1rem 0.75rem; font-size: 0.88rem; }

/* -- badges: default chip is a visible neutral; families keep their palettes --
   :where() gives this rule NO specificity. As a plain `.badge` rule it sat after the families above
   (.badge-triage, .badge-wk-*, .badge-lk-*, .badge-cancelled, .badge-age-* …) and, being equally
   specific and later, painted every one of them grey from 2026-08-30 to 2026-10-02. */
:where(.badge) { background: var(--track); color: var(--ink-muted); }

/* -- board -- */
.board-col { padding: 12px 12px 8px; }
.board-col-header { padding-bottom: 8px; border-bottom: 1px solid var(--border); margin-bottom: 10px; }
.board-col--leave .board-col-header .name { color: var(--ink-muted); }
.score-pill--zero { background: var(--track); color: var(--ink-muted); }
.case-card .doc {
  display: flex; justify-content: space-between; align-items: baseline; gap: 6px;
}
.case-card .doc .badge { font-weight: 600; flex-shrink: 0; }
.case-card .meta { margin-top: 3px; }
.case-card .status-row { margin-top: 6px; }
.board-empty {
  border: 1.5px dashed var(--border); border-radius: 10px; padding: 1rem 0.5rem;
  text-align: center; color: var(--ink-subtle); font-size: 0.85rem; background: var(--surface-sunken);
}

/* -- flash alerts: type-aware -- */
.alert-success { border: 1px solid var(--success); }
.alert-warn {
  background: var(--warning-surface); color: var(--warning);
  border: 1px solid var(--warning);
}
.alert-danger { border: 1px solid var(--danger); }

/* -- detail pages: header row, meta grid, action bar -- */
.detail-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  flex-wrap: wrap; gap: 8px;
}
.detail-head .section-title {
  margin: 0; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.detail-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px 14px; }
.detail-head + .detail-grid { margin-top: 12px; }
.detail-grid .item .k { font-size: 0.74rem; color: var(--ink-muted); margin-bottom: 1px; }
.detail-grid .item .v { font-size: 0.95rem; word-break: break-word; }
.detail-desc { color: var(--ink); font-size: 0.92rem; margin-top: 10px; }

.action-bar {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end;
  border-top: 1px solid var(--border); padding-top: 12px; margin-top: 12px;
}
.action-form { display: flex; gap: 6px; align-items: flex-end; flex-wrap: wrap; }
.action-form .field { margin: 0; }
.action-form .field label { font-size: 0.75rem; margin-bottom: 0.25rem; }
.action-form select, .action-form input[type="text"] {
  padding: 0.5rem 0.7rem; font-size: 0.9rem; border-width: 1.5px; background: var(--surface);
}
.action-hint { color: var(--ink-muted); font-size: 0.85rem; }
@media (max-width: 640px) {
  .action-bar > form { width: 100%; }
  .action-form select, .action-form input[type="text"] { flex: 1 1 auto; min-width: 0; width: auto; }
  .action-bar > .action-solo .btn { width: 100%; }
}

/* -- inline forms (triage, admin add-rows) -- */
.form-inline { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; }
.form-inline .field { margin: 0; }
.form-inline .field.grow { flex: 1 1 220px; }
/* Every box and button in a filter row is one height (--size-control-sm), so labels, boxes and buttons
   line up: date and search inputs used to keep the base padding and stand 60px next to 51px selects
   and 38px buttons (2026-10-05). */
.form-inline :is(select, input:not([type="checkbox"]):not([type="radio"]):not([type="file"])) {
  background: var(--surface); border-width: 1.5px; padding: 0 0.8rem; font-size: 0.92rem;
  height: var(--size-control-sm);
}
.form-inline .btn, .tb-prf .btn { height: var(--size-control-sm); min-height: 0; display: inline-flex; align-items: center; }
/* <span class="form-break"></span> starts a new row of filters. */
.form-inline .form-break { flex-basis: 100%; height: 0; }
/* A filter bar that must stay on one line on a desktop: its fields shrink instead of wrapping. */
@media (min-width: 981px) {
  .form-inline--one-row { flex-wrap: nowrap; }
  /* shares by weight, not by the longest option's width (ประเภท's labels took half the row) */
  .form-inline--one-row .field { flex: 1 1 0; min-width: 0; }
  .form-inline--one-row .field.grow { flex: 1.6 1 0; }
  .form-inline--one-row :is(select, input) { width: 100%; }
  .form-inline--one-row .btn { flex: none; }
}
@media (max-width: 640px) {
  .form-inline .field { flex: 1 1 100%; }
  .form-inline .btn { width: 100%; }
}

/* -- small numeric / month inputs -- */
.num-input {
  width: 70px; padding: 0.45rem 0.4rem; text-align: center; font: inherit;
  border: 1.5px solid var(--border); border-radius: 8px; background: var(--surface); color: var(--text);
}
.num-input--days { width: 90px; }

/* -- owner checkboxes: compact grid instead of a long wrapping row -- */
.owner-checks { display: grid; grid-template-columns: repeat(auto-fill, minmax(165px, 1fr)); gap: 4px 12px; }
.owner-checks label { font-size: 0.83rem; }
.owner-checks input { accent-color: var(--primary); }
/* .td-assign lives with the caretaker picker below (one rule; this 380px copy was dead — the later
   240px one always won, including on /admin/members/…/transfer). */
.td-owners { min-width: 440px; }
.td-owners .owner-checks { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.wl-table input[type="checkbox"] { accent-color: var(--primary); }

/* -- collapsible cards (approval detail: tasks / timeline) -- */
details.card { padding: 0; }
details.card > summary {
  list-style: none; cursor: pointer; user-select: none;
  padding: 0.9rem 1.25rem; font-weight: 700; font-size: 0.92rem; color: var(--brand-text);
  display: flex; align-items: center; gap: 8px;
}
details.card > summary::-webkit-details-marker { display: none; }
details.card > summary::after {
  content: "▾"; margin-left: auto; color: var(--ink-subtle); transition: transform 0.15s;
}
details.card[open] > summary::after { transform: rotate(180deg); }
details.card > .collapse-body { padding: 0 1.25rem 1.1rem; }
.summary-count {
  background: var(--track); color: var(--ink-muted); border-radius: 999px;
  padding: 1px 9px; font-size: 0.75rem; font-weight: 600;
}
details.collapse-mt { margin-top: 1rem; }
.remark-list--flush { margin-bottom: 0; }
.remark-empty--flush { margin-bottom: 0; padding: 0.25rem 0; }
.form-field-table { margin-top: 4px; }

/* -- timeline: dots on the rail -- */
.timeline li {
  position: relative; border-left: 2px solid var(--border); margin-left: 6px;
  padding: 2px 0 14px 16px; font-size: 0.88rem;
}
.timeline li:last-child { padding-bottom: 2px; }
.timeline li::before {
  content: ""; position: absolute; left: -6px; top: 7px; width: 10px; height: 10px;
  border-radius: 50%; background: var(--primary); border: 2px solid var(--surface);
  box-shadow: 0 0 0 1px var(--border);
}
.timeline li.empty { border-left: none; color: var(--ink-subtle); }
.timeline li.empty::before { display: none; }

/* -- approval form data rows -- */
.form-field-row .k { margin-bottom: 1px; }
.form-field-row .v code {
  display: inline-block; max-width: 100%; overflow-x: auto; white-space: pre-wrap;
}

/* -- triage banner -- */
.triage-banner { font-size: 0.92rem; }
.triage-banner a { color: var(--warning); font-weight: 700; }

/* -- triage / generic case cards -- */
.stack-card { margin-bottom: 12px; }
.case-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.case-head .doc-no { font-weight: 700; }
.case-head a { color: var(--brand-text); }
.case-meta { color: var(--ink-muted); font-size: 0.85rem; margin-top: 4px; }
.case-desc { color: var(--ink); font-size: 0.87rem; margin-top: 4px; }
.stack-card .form-inline { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }

/* -- misc -- */
.footnote { color: var(--ink-muted); font-size: 0.8rem; margin-top: 0.5rem; }
.hint-text { color: var(--ink-muted); font-size: 0.85rem; margin: -0.25rem 0 0.75rem; }
.page-content .login-wrapper { min-height: 0; padding: 10vh 1.5rem 3rem; }
.totals-row td { font-weight: 700; background: var(--surface-sunken); }
.add-row-form { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.page-content .btn-block { width: 100%; }
.denied-card { max-width: 560px; margin: 2rem auto 0; text-align: center; }
.denied-text { color: var(--ink-muted); margin-bottom: 1.25rem; }

/* ===== Approval redesign (2026-09-05): tabs, caretaker chips, multi-select dropdown,
   due-date badge, KPI tiles, note form. Append-only. ===== */
.tabs {
  display: flex; gap: 4px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
  border-bottom: 2px solid var(--border); margin: 0 0 14px;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  flex-shrink: 0; padding: 8px 14px; margin-bottom: -2px; text-decoration: none; color: var(--ink);
  border-bottom: 3px solid transparent; font-size: 0.9rem; font-weight: 600; white-space: nowrap;
}
.tab:hover { color: var(--brand-text); }
.tab.active { color: var(--brand-text); border-bottom-color: var(--primary); }
.tab-count {
  background: var(--track); color: var(--ink-muted); border-radius: 999px; padding: 0 7px;
  font-size: 0.72rem; font-weight: 700; margin-left: 2px;
}
.tab.active .tab-count { background: var(--primary); color: var(--on-brand); }

.chip {
  display: inline-block; background: var(--track); color: var(--ink); border-radius: 999px;
  padding: 2px 9px; font-size: 0.78rem; font-weight: 600; white-space: nowrap; margin: 1px 3px 1px 0;
}
.muted { color: var(--ink-subtle); }
.small { font-size: 0.75rem; }
.td-person, .td-owners-chips { white-space: nowrap; }
.wl-row-due { background: var(--warning-surface); }
.badge-due-ok { background: var(--track); color: var(--pill-success); }

/* multi-select caretaker dropdown: a details/summary popover, no JS */
.owner-picker-form { display: inline-block; position: relative; }
.owner-picker { position: relative; }
.owner-picker > summary {
  list-style: none; cursor: pointer; user-select: none; display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 10px; border: 1.5px solid var(--border); border-radius: 8px; background: var(--surface);
  font-size: 0.85rem; white-space: nowrap; max-width: 320px; overflow: hidden; text-overflow: ellipsis;
}
.owner-picker > summary::-webkit-details-marker { display: none; }
.owner-picker > summary .caret { color: var(--ink-subtle); }
.owner-picker[open] > summary { border-color: var(--primary); }
.owner-picker-menu {
  position: absolute; z-index: 30; top: calc(100% + 4px); left: 0; min-width: 260px;
  background: var(--surface); border: 1.5px solid var(--border); border-radius: 10px; padding: 10px;
  box-shadow: 0 8px 24px rgba(0,0,0,.12); display: flex; flex-direction: column; gap: 6px;
}
.owner-picker-opt { display: flex; align-items: center; gap: 7px; font-size: 0.85rem; line-height: 1.45; cursor: pointer; white-space: nowrap; }   /* its own line height: the same rows in a table cell and in a form field */
.owner-picker-opt input { accent-color: var(--primary); }
.owner-picker-flag { border-top: 1px solid var(--border); padding-top: 8px; margin-top: 2px; color: var(--ink-muted); font-size: 0.8rem; }
.owner-picker-menu .btn { margin-top: 4px; }
.owner-picker-foot { display: flex; flex-direction: column; gap: 6px; }
/* The one .td-assign rule (approval lists + the transfer page's target selects). */
.td-assign { min-width: 240px; }
/* static/owner-picker.js (2026-09-27): while open, the menu floats above the table's scroll box
   (position: fixed, placed from the summary) instead of being clipped by it; long rosters scroll
   inside the menu and the submit stays pinned at its bottom. */
.owner-picker-menu.is-floating {
  position: fixed; z-index: 70; overflow-y: auto; overscroll-behavior: contain; padding-bottom: 0;
}
.owner-picker-menu.is-floating .owner-picker-opt { white-space: normal; overflow-wrap: anywhere; }
.owner-picker-menu.is-floating .owner-picker-foot {
  position: sticky; bottom: 0; background: var(--surface); padding-bottom: 10px;
}
/* Approval detail header: a long caretaker chip ("Mew-Procurement & Purchasing") wraps inside its
   own grid cell instead of running over วันกำหนดส่ง next to it. */
.detail-grid > .item { min-width: 0; }
.detail-grid .item .v .chip { white-space: normal; overflow-wrap: anywhere; max-width: 100%; }
/* Approval list tabs: filter count + bulk bar hint. เจ้าของงาน / ผู้ดูแลงาน wrap inside a bounded
   column: Lark names resolved to "Name-Department" (e.g. "Punch - RD 🌈-Product Innovation & R&D")
   kept on one line pushed มอบหมายให้ off a 1366px screen once the tick column was added. */
.appr-table .td-person { white-space: normal; min-width: 140px; max-width: 220px; overflow-wrap: anywhere; }
.appr-table .td-owners-chips { white-space: normal; min-width: 120px; max-width: 220px; }
.appr-table tr[id] { scroll-margin-top: 150px; }   /* #a<id> after an assign clears the sticky header */
.appr-filter__count { margin: -4px 0 10px; }
.appr-bulk__hint { font-size: 0.78rem; color: var(--ink-muted); flex: 1 1 260px; }

/* KPI tiles */
.kpi-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin: 0 0 14px; align-items: stretch; }
.kpi-tile { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; }
.kpi-tile .k { color: var(--ink-muted); font-size: 0.74rem; }
.kpi-tile .v { font-size: 1.35rem; font-weight: 700; color: var(--ink); line-height: 1.2; margin-top: 2px; }
.kpi-tile .v small { font-size: 0.75rem; color: var(--ink-muted); font-weight: 500; }
.kpi-tile--alert { border-color: var(--danger); background: var(--danger-surface); }
.kpi-tile--alert .v { color: var(--danger); }
.kpi-more { align-self: center; color: var(--ink); font-size: 0.85rem; text-decoration: none; font-weight: 600; }

/* KPI levels (junior / mid / senior) */
.level-badge {
  display: inline-block; border-radius: 999px; padding: 1px 9px; font-size: 0.74rem; font-weight: 700;
  vertical-align: middle; margin-left: 4px;
}
.level-junior { background: var(--info-surface); color: var(--pill-info); }
.level-mid { background: var(--warning-surface); color: var(--pill-warning); }
.level-senior { background: var(--seasonal-surface); color: var(--seasonal); }
.kpi-tile--ok { border-color: var(--border); background: var(--success-surface); }
.kpi-tile--ok .v { color: var(--success); }
.kpi-tile--warn { border-color: var(--warning-dot); background: var(--warning-surface); }
.kpi-tile--warn .v { color: var(--warning); }
.kpi-grade-card { margin-bottom: 14px; }
.kpi-grade tr.kpi-ok td:last-child { color: var(--success); font-weight: 600; }
.kpi-grade tr.kpi-fail td:last-child { color: var(--danger); font-weight: 600; }
.num-input--select { width: auto; padding: 0.45rem 0.6rem; text-align: left; }

/* notes */
.check-inline { display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; color: var(--ink); }
.check-inline input { accent-color: var(--primary); }
.attach-links { display: flex; flex-wrap: wrap; gap: 6px 12px; margin-top: 4px; font-weight: 500; font-size: 0.85rem; }
.attach-links a { color: var(--brand-text); }
/* Files of a Lark Approval form (2026-10-04). Inside an item-table cell: one file per line, a long
   file name wraps inside the cell instead of widening the table. An expired signed link is grey text. */
.attach-links a, .attach-links .file-expired { overflow-wrap: anywhere; }
.attach-links--cell { flex-direction: column; flex-wrap: nowrap; gap: 3px; margin-top: 0; min-width: 7.5rem; max-width: 17rem; font-size: inherit; }
.file-expired { color: var(--ink-muted); font-weight: 400; }
.file-expired small { white-space: nowrap; }
.files-expired { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin: 0 0 8px; padding: 8px 12px;
  border-radius: 8px; background: var(--warning-surface); color: var(--warning); font-size: 0.85rem; }
.apr-anchor { scroll-margin-top: 90px; }      /* #notes / #history from the bell clear the sticky header */
.num-input--text { width: 150px; text-align: left; }
.profile-form { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }

/* ===== report history chart (2026-08-30) — palette validated via dataviz six checks:
   PR cat-1 / PO cat-2 / approvals cat-3 (One Platform categorical order, never cycled) ===== */
.chart-legend { display: flex; gap: 16px; margin-bottom: 12px; font-size: 0.82rem; color: var(--ink); }
.chart-legend .sw { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 5px; vertical-align: -1px; }
.sw-pr { background: var(--cat-1); }
.sw-po { background: var(--cat-2); }
.sw-appr { background: var(--cat-3); }
.hbar-row { display: flex; align-items: center; gap: 10px; margin-bottom: 7px; }
.hbar-name { flex: 0 0 180px; text-align: right; font-size: 0.82rem; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hbar-track { flex: 1; display: flex; align-items: center; gap: 8px; min-width: 0; }
.hbar-bar { display: flex; height: 18px; border-radius: 0 4px 4px 0; overflow: hidden; min-width: 3px; }
.seg { height: 100%; }
.seg + .seg { margin-left: 2px; }
.seg-pr { background: var(--cat-1); }
.seg-po { background: var(--cat-2); }
.seg-appr { background: var(--cat-3); }
.hbar-total { font-size: 0.8rem; font-weight: 600; color: var(--ink); flex: 0 0 auto; }
@media (max-width: 640px) { .hbar-name { flex-basis: 108px; } }

/* ===== supplier master (ทะเบียน Vendor) hint + card (2026-09-08) ===== */
.supplier-hint { font-size: 0.84rem; color: var(--ink); background: var(--track); border: 1px solid var(--border);
  border-radius: 6px; padding: 6px 10px; margin: 8px 0 4px; }
.supplier-hint a { color: var(--brand-text); }
.checkbox-inline { display: flex; align-items: center; gap: 6px; font-weight: 400; font-size: 0.85rem; }

/* ===== approval list filter bar (2026-09-10) ===== */
.filter-card { margin-bottom: 14px; }
.filter-card input[type="search"] { width: 100%; }

/* ===== "+ ดูรายการสินค้า" line-item expander (2026-09-10) ===== */
.case-card-main { display: block; color: inherit; text-decoration: none; }
.items-exp { margin-top: 6px; }
.items-exp > summary { cursor: pointer; list-style: none; font-size: 0.78rem; color: var(--ink);
  display: inline-flex; align-items: center; gap: 5px; padding: 2px 0; }
.items-exp > summary::-webkit-details-marker { display: none; }
.items-exp .exp-sign { display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border: 1px solid var(--border); border-radius: 4px; background: var(--track);
  font-weight: 700; line-height: 1; }
.items-exp > summary .exp-sign::after { content: "+"; }
.items-exp[open] > summary .exp-sign::after { content: "−"; }
.items-wrap { overflow-x: auto; margin-top: 6px; }
.items-table { width: 100%; border-collapse: collapse; font-size: 0.78rem; }
.items-table th, .items-table td { border-bottom: 1px solid var(--border); padding: 4px 7px; text-align: left; vertical-align: top; }
.items-table th { background: var(--surface-sunken); font-weight: 600; color: var(--ink); white-space: nowrap; }
.items-table .num { text-align: right; white-space: nowrap; }
.items-table .item-sub { font-size: 0.72rem; color: var(--ink-muted); }

/* ===== delivery calendar (2026-09-10) ===== */
.cal-head { display: flex; align-items: center; gap: 12px; margin: 4px 0 8px; font-size: 1rem; }
.cal-wrap { overflow-x: auto; padding: 8px; }
.cal { width: 100%; border-collapse: separate; border-spacing: 4px; table-layout: fixed; min-width: 820px; }
.cal th { font-size: 0.75rem; color: var(--ink-muted); font-weight: 600; padding-bottom: 2px; }
.cal-cell { vertical-align: top; height: 96px; border: 1px solid var(--border); border-radius: 8px;
  padding: 4px 5px; background: var(--surface); }
.cal-out { background: var(--surface-sunken); opacity: 0.55; }
.cal-today { border-color: var(--brand-600); box-shadow: inset 0 0 0 1px var(--brand-600); }
.cal-picked { background: var(--track); border-color: var(--brand-600); }
.cal-daylink { display: flex; align-items: center; justify-content: space-between;
  text-decoration: none; color: var(--ink); font-size: 0.78rem; font-weight: 700; }
.cal-count { background: var(--brand-600); color: var(--on-brand); border-radius: 10px; padding: 0 6px;
  font-size: 0.7rem; font-weight: 700; }
.cal-item { font-size: 0.7rem; line-height: 1.25; margin-top: 3px; padding: 2px 4px;
  background: var(--track); border: 1px solid var(--border-strong); border-radius: 6px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-item .cal-loc { color: var(--ink-muted); display: block; }
.cal-more { font-size: 0.68rem; color: var(--ink-muted); margin-top: 2px; }
.items-table--flush { font-size: 0.75rem; }
.items-table--flush td { border: 0; padding: 1px 6px 1px 0; }
.deliver-form { margin-top: 10px; }
/* rounds: time + edit (2026-09-11) */
.round-time { font-size: 0.72rem; color: var(--ink-muted); font-weight: 600; }
.round-actions { white-space: nowrap; }
.round-actions .inline-form { display: inline; }
.round-edit:not([open]) { display: none; }   /* opened by its row's แก้ไข link (?edit=id) */
.round-edit { scroll-margin-top: 150px; }      /* the #anchor jump must clear the sticky header */

/* calendar: the whole day cell is the target */
.cal-cell[data-date] { cursor: pointer; transition: background-color .12s, border-color .12s; }
.cal-cell[data-date]:hover { background: var(--surface-hover); border-color: var(--brand-600); }
.cal-daylink:focus-visible { outline: 2px solid var(--brand-600); outline-offset: 2px; border-radius: 4px; }
.cal-item .cal-time { font-weight: 700; color: var(--ink); margin-right: 4px; font-variant-numeric: tabular-nums; }

/* the day window */
/* margin:auto is what centres a modal <dialog>; the app's global margin reset had pinned it top-left */
.day-dialog { margin: auto; border: 0; padding: 0; border-radius: 14px; width: min(980px, calc(100vw - 24px));
  max-height: calc(100vh - 32px); box-shadow: 0 24px 60px rgba(16, 40, 26, .28); color: var(--ink); }
.day-dialog :focus-visible { outline: 2px solid var(--brand-600); outline-offset: 2px; }
.day-round__top a { color: var(--brand-text); text-decoration: none; }
.day-round__top a:hover { text-decoration: underline; }
.day-dialog::backdrop { background: rgba(18, 32, 24, .45); }
.day-dialog__frame { display: flex; flex-direction: column; max-height: calc(100vh - 32px); }
.day-dialog__head { display: flex; align-items: center; gap: 10px; padding: 14px 18px;
  border-bottom: 1px solid var(--border); background: var(--surface-sunken); }
.day-dialog__titles { flex: 1; min-width: 0; }
.day-dialog__title { margin: 0; font-size: 1.12rem; color: var(--ink); }
.day-dialog__sub { font-size: 0.8rem; color: var(--ink-muted); margin-top: 2px; }
.day-dialog__close { border: 0; background: transparent; font-size: 1.25rem; line-height: 1; cursor: pointer;
  color: var(--ink-muted); padding: 6px 9px; border-radius: 6px; }
.day-dialog__close:hover { background: var(--surface-hover); }
.day-dialog__body { overflow-y: auto; padding: 14px 18px; }
.day-dialog__foot { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; padding: 10px 18px;
  border-top: 1px solid var(--border); }
.day-filter-note { font-size: 0.78rem; color: var(--warning); background: var(--warning-surface); border-radius: 6px;
  padding: 5px 9px; margin-bottom: 10px; }
.day-locs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; font-size: 0.78rem; }
.day-loc-chip { background: var(--track); border-radius: 999px; padding: 2px 10px; color: var(--ink-muted); }
.day-rounds { list-style: none; margin: 0; padding: 0; }
.day-round { display: grid; grid-template-columns: 84px 1fr; gap: 14px; padding: 12px 0; border-top: 1px solid var(--border); }
.day-round:first-child { border-top: 0; }
.day-round__time { text-align: right; padding-top: 1px; }
.day-round__time b { font-size: 1.15rem; color: var(--ink); font-variant-numeric: tabular-nums; }
.day-round__time b + span { font-size: 0.72rem; color: var(--ink-muted); margin-left: 3px; }
.day-round__time .muted { font-size: 0.74rem; }
.day-round__main { min-width: 0; }
.day-round__top { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px; }
.day-round__place { font-size: 0.84rem; font-weight: 600; color: var(--ink); }
.day-round__meta { font-size: 0.78rem; color: var(--ink-muted); margin: 2px 0 6px; }
.day-round__note { font-size: 0.78rem; color: var(--ink-muted); margin-top: 4px; }
@media (max-width: 640px) {
  .day-round { grid-template-columns: 1fr; gap: 4px; }
  .day-round__time { text-align: left; display: flex; gap: 6px; align-items: baseline; }
  .day-round__time b { display: inline; }
}
@media (max-width: 640px) { .cal-cell { height: 78px; } .cal-item { font-size: 0.62rem; } }
.chip-co { background: var(--track); color: var(--ink); margin-left: 4px; font-size: 0.68rem; }

/* ===== PO dashboard (2026-09-11) ===== */
.dash-presets { margin-top: 8px; font-size: 0.8rem; color: var(--ink-muted); display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.chip-link { display: inline-block; padding: 2px 10px; border-radius: 999px; background: var(--track); color: var(--brand-text);
  text-decoration: none; font-size: 0.78rem; white-space: nowrap; }
.chip-link:hover { background: var(--surface-hover); }
.chip-link.is-on { background: var(--brand-600); color: var(--on-brand); }
.dash-active { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 0 0 12px; font-size: 0.8rem; color: var(--ink-muted); }
.dash-nav { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }
.dash-anchor { scroll-margin-top: 150px; }
.kpi-sub { font-size: 0.72rem; color: var(--ink-muted); margin-top: 2px; }
.seg-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.seg-toggle a { padding: 4px 12px; font-size: 0.8rem; color: var(--brand-text); text-decoration: none; }
.seg-toggle a + a { border-left: 1px solid var(--border); }
.seg-toggle a.is-on { background: var(--brand-600); color: var(--on-brand); }
.chart-scroll { overflow-x: auto; }
.dash-chart { width: 100%; min-width: 560px; height: auto; display: block; }
.dash-chart .grid-line { stroke: var(--border); stroke-width: 1; }
.dash-chart .base-line { stroke: var(--border-strong); stroke-width: 1; }
.dash-chart .axis-label { font-size: 10px; fill: var(--ink-muted); }
.dash-chart .bar { fill: var(--cat-1); }
.dash-chart .bar-hit { fill: transparent; }
.dash-chart .bar-group:hover .bar { fill: color-mix(in srgb, var(--cat-1) 82%, var(--ink)); }   /* a small step, not a jump to full contrast */
.dash-chart .bar-group:hover .bar-hit { fill: color-mix(in srgb, var(--ink) 5%, transparent); }
.dash-chart .price-line { fill: none; stroke: var(--cat-1); stroke-width: 2; stroke-linejoin: round; }
.dash-chart .price-dot { fill: var(--cat-1); stroke: var(--surface); stroke-width: 2; }
.dash-chart .price-hit { fill: transparent; }
.dash-chart .price-point:hover .price-dot { fill: var(--brand-700); }
.dash-table .num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.dash-rank a { color: var(--brand-text); text-decoration: none; }
.dash-rank a:hover { text-decoration: underline; }
.dash-bar { display: flex; align-items: center; gap: 8px; min-width: 220px; }
.dash-bar__track { flex: 1; min-width: 90px; }
.dash-bar__track span { display: block; height: 14px; background: var(--cat-1); border-radius: 0 4px 4px 0; min-width: 2px; }
.dash-bar b { font-size: 0.8rem; font-weight: 600; white-space: nowrap; min-width: 92px; text-align: right;
  font-variant-numeric: tabular-nums; }
.dash-warn { color: var(--warning); }
.dash-focus-head { display: flex; flex-wrap: wrap; gap: 4px 16px; align-items: baseline; margin-bottom: 8px; font-size: 0.85rem; }
.dash-exports { display: flex; gap: 6px; flex-wrap: wrap; }
.price-up { color: var(--danger); font-weight: 600; }
.price-best { color: var(--ink); font-weight: 600; }
.nick-chip { font-size: 0.7rem; background: var(--track); color: var(--ink); border-radius: 999px; padding: 0 7px; margin-left: 5px; white-space: nowrap; }

/* --- notification bell + Pipeline delivery-schedule suggestions (2026-09-12) --- */
.bell { position: relative; text-decoration: none; font-size: 1.05rem; line-height: 1; margin-right: 10px; }
.bell.has-unread .bell-count { position: absolute; top: -7px; right: -9px; background: var(--danger-solid); color: var(--on-brand);
  font-size: 0.62rem; font-weight: 700; border-radius: 999px; padding: 1px 5px; min-width: 15px; text-align: center; }
/* The bell PAGE (the list, its chips, legend and filters) has its own stylesheet since 2026-10-04:
   static/bell.css, linked by templates/notifications.html. Only the header's bell is styled here. */
.suggest-card { border: 1px solid var(--brand-600); border-radius: 8px;
  background: var(--surface-sunken); padding: 12px 14px; margin-bottom: 14px; }
.suggest-head { font-weight: 600; margin-bottom: 6px; }
.suggest-source { font-size: 0.72rem; color: var(--ink-muted); font-weight: 400; margin-left: 6px; }
.suggest-log { white-space: pre-wrap; font-size: 0.8rem; color: var(--ink); background: var(--surface);
  border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px; margin: 8px 0; max-height: 220px; overflow: auto; }
.suggest-warn { color: var(--warning); font-size: 0.82rem; margin-top: 6px; }
.suggest-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }

/* --- "view as user" banner (2026-09-12): unmissable while impersonating --- */
.view-as-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; background: var(--warning-surface); border: 1px solid var(--warning);
  color: var(--warning); border-radius: 8px; padding: 8px 12px; margin: 0 0 12px; font-size: 0.86rem; }
.view-as-bar b { font-weight: 700; }
.view-as-bar .btn { white-space: nowrap; }
.view-as-pick { display: flex; gap: 6px 10px; align-items: flex-end; flex-wrap: wrap; }   /* the button sits on the select's line */
.view-as-pick .btn { box-shadow: none; }
.view-as-log { font-size: 0.78rem; color: var(--ink-muted); }

/* โอนงาน (offboarding) — the action cell holds a link and a form side by side. */
.member-actions { white-space: nowrap; }
.member-actions .btn { margin-right: 6px; }
.member-actions .inline-form { display: inline-block; }

/* ===== phone pass (2026-09-13) =====
   Scope: the pages that actually get opened on a phone — ปฏิทินส่งของ, เคสของฉัน, แจ้งเตือน —
   plus the nav, which is on every page. The two spend dashboards stay desktop-first by choice. */

/* The month grid needs 820px to be readable, so below 700px it is replaced by the day-by-day
   agenda list rendered in calendar.html. Desktop is untouched. */
.cal-agenda { display: none; }
@media (max-width: 700px) {
  .cal-wrap { display: none; }
  .cal-agenda { display: block; }
  .cal-agenda__day { background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
    padding: 8px 10px; margin-bottom: 8px; }
  .cal-agenda__day.is-today { border-color: var(--brand-600); box-shadow: inset 0 0 0 1px var(--brand-600); }
  .cal-agenda__head { display: flex; align-items: center; justify-content: space-between; gap: 8px;
    min-height: 34px; text-decoration: none; color: var(--ink); font-weight: 700; font-size: 0.9rem; }
  /* in the agenda a round may wrap onto two lines — the grid's one-line ellipsis would hide the place */
  .cal-agenda .cal-item { font-size: 0.82rem; white-space: normal; margin-top: 5px; padding: 4px 6px; }
  .cal-agenda .cal-loc { display: inline; margin-left: 4px; }
}

/* Comfortable tap targets on the phone-facing pages. Deliberately not applied to the dashboards:
   there a row link sits inside a dense table where extra height would cost more than it gains. */
@media (max-width: 700px) {
  .page-toolbar .btn, .filter-card .btn, .cal-head .btn { min-height: 36px; display: inline-flex;
    align-items: center; justify-content: center; }
}

/* --- PR request line items: row editor + per-item files (2026-09-15) --- */
.item-rows { display: flex; flex-direction: column; gap: 10px; margin-bottom: 8px; }
.item-row { border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; background: var(--surface-sunken); }
.item-row__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; font-size: 0.82rem; color: var(--ink); }
.item-row .item-row__grid { grid-template-columns: 2fr 2fr 0.8fr 0.8fr; gap: 8px 10px; margin-bottom: 6px; }
@media (max-width: 700px) { .item-row .item-row__grid { grid-template-columns: 1fr 1fr; } }
.item-row__files { margin-bottom: 0; }
.item-rows__actions { margin-bottom: 14px; }
.item-previews { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.item-preview { display: inline-flex; align-items: center; gap: 6px; font-size: 0.78rem; color: var(--ink); }
.item-preview img, .thumb { width: 56px; height: 56px; object-fit: cover; border-radius: 6px; border: 1px solid var(--border); background: var(--surface); vertical-align: middle; }
.item-files { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; }
.item-files a { color: var(--brand-text); font-size: 0.82rem; }
.item-upload { display: inline-flex; gap: 6px; align-items: center; margin-top: 6px; }
.item-upload input[type=file] { font-size: 0.76rem; max-width: 200px; }
.prq-items td { vertical-align: top; }
.attach-list { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.attach-item { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; font-size: 0.85rem; font-weight: 500; }
.attach-item a { color: var(--brand-text); }
.attach-move select { font-size: 0.78rem; padding: 3px 6px; }

/* --- คำขอ PR: picture gallery (2026-09-16, Kuang: show pictures as pictures, arrows to step) --- */
.thumb-lg { width: 96px; height: 96px; cursor: zoom-in; }
/* A native modal <dialog> (2026-10-06): full screen, flex only while open, the browser's box styles reset. */
.lightbox { position: fixed; inset: 0; width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: 0; border: 0;
  background: rgba(0, 0, 0, 0.88); align-items: center; justify-content: center; }
.lightbox[open] { display: flex; }
.lightbox::backdrop { background: transparent; }
/* An author `display:` rule beats the browser's own [hidden] styling, so anything toggled with
   the hidden attribute stays on screen unless this says otherwise. It has caught us three times
   now (the lightbox and the mention menu below, then the คำขอ PR header card on 2026-09-19 —
   where every assertion passed and only a screenshot showed it). One rule, once, for the app. */
[hidden] { display: none !important; }
.lightbox img { max-width: min(92vw, 1400px); max-height: 82vh; object-fit: contain; border-radius: 6px; background: #111; }
.lightbox-btn { position: absolute; top: 50%; transform: translateY(-50%); width: 52px; height: 52px; border-radius: 50%; border: 0; background: rgba(255, 255, 255, 0.18); color: #fff; font-size: 28px; line-height: 1; cursor: pointer; }
.lightbox-btn:hover { background: rgba(255, 255, 255, 0.35); }
.lightbox-prev { left: 14px; }
.lightbox-next { right: 14px; }
.lightbox-close { position: absolute; top: 12px; right: 14px; width: 44px; height: 44px; border: 0; border-radius: 50%; background: rgba(255, 255, 255, 0.18); color: #fff; font-size: 24px; line-height: 1; cursor: pointer; }
.lightbox-cap { position: absolute; left: 0; right: 0; bottom: 0; padding: 12px 72px; color: #eee; font-size: 0.9rem; text-align: center; background: linear-gradient(transparent, rgba(0, 0, 0, 0.7)); }
.lightbox-cap a { color: #7cb0ff; margin-left: 10px; }
.lightbox-count { color: #bbb; margin-right: 10px; }
@media (max-width: 700px) {
  .lightbox-btn { width: 44px; height: 44px; font-size: 24px; }
  .lightbox-cap { padding: 10px 50px; font-size: 0.8rem; }
  .thumb-lg { width: 80px; height: 80px; }
}

/* --- คำขอ PR: @-tag composer --- */
.mention-box { position: relative; }
.mention-menu { position: absolute; left: 0; right: 0; z-index: 70; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12); max-height: 260px; overflow: auto; }
.mention-menu[hidden] { display: none; }
.mention-item { padding: 8px 12px; cursor: pointer; display: flex; justify-content: space-between; gap: 10px; font-size: 0.9rem; }
.mention-item.active, .mention-item:hover { background: var(--surface-hover); }
.mention-item .dept { color: var(--ink-muted); font-size: 0.8rem; }
.mention-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.mention-chip { display: inline-flex; align-items: center; gap: 6px; background: var(--track); color: var(--pill-success); border-radius: 999px; padding: 2px 10px; font-size: 0.82rem; }
.mention-chip button { border: 0; background: none; color: var(--pill-success); cursor: pointer; font-size: 1rem; line-height: 1; padding: 0; }
.mention { color: var(--ink); font-weight: 600; }
/* หมายเหตุ ของ Approval: แก้ไข / ลบ (2026-10-05). Two small folded controls under a note the viewer may
   change (plain <details>, no script); an open one takes the row to itself. The edit box is a
   .mention-box, so the @-menu opens under its own textarea. Phone: thumb-sized summaries. */
.note-tools { display: flex; flex-wrap: wrap; gap: 6px 10px; margin-top: 8px; }
.note-tool > summary { display: inline-flex; align-items: center; min-height: 30px; padding: 2px 12px; cursor: pointer;
  list-style: none; font-size: 0.8rem; color: var(--ink-muted); border: 1px solid var(--border); border-radius: 999px; background: var(--surface); }
.note-tool > summary::-webkit-details-marker { display: none; }
.note-tool--del > summary { color: var(--danger); border-color: var(--border-strong); }
.note-tool[open] { flex: 1 1 100%; min-width: 0; }
.note-tool[open] > summary { margin-bottom: 8px; background: var(--surface-hover); }
.note-tool--del[open] > summary { background: var(--danger-surface); }
.note-tool__form { margin: 0; }
.note-tool__form textarea { background: var(--surface); }
.note-tool__form .footnote { margin: 6px 0 0; }
.note-tool__ask { margin: 0 0 8px; font-size: 0.9rem; overflow-wrap: anywhere; }
.remark-item[data-note] .remark-meta { overflow-wrap: anywhere; }   /* Lark's own refusal words can be one long token */
/* "โพสต์เป็นคอมเมนต์ใน Lark Approval ด้วย" remembers each person's last choice (2026-10-07). A TICKED box sends
   the note where the requester reads it, so it is never quiet: the label is lit whenever it is ticked
   (from memory or by hand), and the line that says it came ticked from memory sits on a row of its own —
   gone again once the box is unticked. */
.note-lark-box { padding: 3px 9px; border: 1px solid transparent; border-radius: 8px; }
.note-lark-box:has(input:checked) { background: var(--warning-surface); border-color: var(--warning-dot); color: var(--warning); font-weight: 600; }
.note-lark-on { flex: 1 1 100%; min-width: 0; padding: 4px 9px; font-size: 0.82rem; color: var(--warning); background: var(--warning-surface);
  border: 1px solid var(--warning-dot); border-radius: 8px; overflow-wrap: anywhere; }
.inline-actions:has(.note-lark-box input:not(:checked)) > .note-lark-on { display: none; }
@media (max-width: 640px) {
  .note-tool > summary { min-height: 40px; padding: 4px 16px; font-size: 0.86rem; }
  .note-tool__form .btn { min-height: 40px; }
  .note-tool--del .note-tool__form .btn { width: 100%; }
}
/* rich_text filter (2026-09-27): pasted http(s) links in any free-text block. Shortened text, but a
   long unbroken address must still wrap inside a phone-width card rather than push it sideways. */
.rt-link { overflow-wrap: anywhere; word-break: break-word; }

.file-entry { display: inline-flex; align-items: center; gap: 4px; }
.dl-link { color: var(--brand-text); font-size: 0.82rem; text-decoration: none; padding: 2px 6px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); white-space: nowrap; }
.dl-link:hover { background: var(--surface-hover); }
.readonly-value { padding: 0.55rem 0; }

/* Removing an attachment: the 🗑 reveals an explicit ยืนยันลบ, so one stray tap removes nothing. */
.attach-del { display: inline-flex; align-items: center; gap: 6px; }
.attach-del__ask { padding: 2px 8px; line-height: 1.4; }
.attach-del__confirm { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.attach-del__q { font-size: 0.78rem; color: var(--danger); max-width: 16rem; overflow-wrap: anywhere; }
.item-files .attach-del { margin-left: 4px; }
/* งวดงาน donut (Praew, 2026-09-19: "Shape แสดง สัดส่วนเป็น วงกลม"). A conic-gradient ring — no
   chart library, no image — with the number inside it, so it does not depend on colour alone. */
.stage { display: inline-flex; align-items: center; gap: 6px; vertical-align: middle; }
.stage-ring {
  --pct: 0; --size: 34px;
  width: var(--size); height: var(--size); border-radius: 50%; flex: none;
  display: inline-grid; place-items: center;
  background: conic-gradient(var(--brand-600) calc(var(--pct) * 1%), var(--track) 0);
}
.stage-ring__num {
  width: calc(var(--size) - 9px); height: calc(var(--size) - 9px); border-radius: 50%;
  background: var(--surface); display: grid; place-items: center;
  font-size: 0.62rem; font-weight: 700; color: var(--ink);
}
.stage-txt { font-size: 0.78rem; font-weight: 600; color: var(--ink); white-space: nowrap; }
.stage-inputs { display: flex; align-items: center; gap: 8px 14px; flex-wrap: wrap; }
.stage-inputs input { width: 4.5rem; }
/* Each box with its caption (งวดที่ / คืบหน้า … %) on one line. Two classes, to outrank the
   `.field label` block rule: these are captions beside a box, not a field heading. */
.stage-inputs .stage-in { display: inline-flex; align-items: center; gap: 6px; margin: 0; white-space: nowrap;
  font-size: 0.82rem; font-weight: 600; color: var(--ink); }

/* สถานะจ่าย, shaped like TRCloud's own PO list: the percentage over a bar, total underneath. */
.pay { font-size: 0.8rem; }
.pay + .pay { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); }
.pay-no { font-weight: 700; color: var(--ink); text-decoration: none; white-space: nowrap; }
.pay-no:hover { text-decoration: underline; }
.pay-no--unknown { color: var(--warning); font-weight: 600; }
.pay-pct { font-size: 0.82rem; font-weight: 700; color: var(--ink); }
.pay-bar { height: 8px; border-radius: 5px; background: var(--track); overflow: hidden; max-width: 190px; }
.pay-bar > span { display: block; height: 100%; background: var(--warning-dot); }
.pay-total { font-weight: 700; color: var(--ink); }
.pay-meta { font-size: 0.75rem; }
.pay--compact { font-size: 0.74rem; }
.pay--compact .pay-bar { height: 6px; max-width: 110px; }
.pay-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px 18px; }
.pay-item__name { font-weight: 600; margin-bottom: 2px; }
.td-pay { min-width: 130px; }
/* PR No. (TRCloud) under a request number / beside a PO (2026-10-02). Each piece stays whole but
   the "จาก PO" tag may drop under its number, so the first column of the คำขอ PR list — already the
   width of "REQ-2026-0030 💬", in a table wider than a 1366 screen — does not grow by a pixel. */
.prq-pr { font-size: 0.76rem; line-height: 1.35; margin-top: 2px; white-space: normal; font-weight: 400; }
.prq-pr__no { font-weight: 700; color: var(--ink); text-decoration: none; white-space: nowrap; }
a.prq-pr__no:hover { text-decoration: underline; }
span.prq-pr__no { color: var(--ink); }
.prq-pr__no.prq-pr__no--text { font-weight: 500; white-space: normal; overflow-wrap: anywhere; }
.prq-pr__tag { display: inline-block; padding: 0 5px; border-radius: 8px; font-size: 0.66rem; white-space: nowrap;
  font-weight: 600; line-height: 1.5; background: var(--warning-surface); color: var(--pill-warning); border: 1px solid var(--warning); vertical-align: 1px; }
.prq-pr__pct { color: var(--ink-muted); font-size: 0.7rem; white-space: nowrap; }
.prq-pr__more { color: var(--ink-muted); }
.prq-list-table td:first-child .prq-pr__no--text { display: inline-block; max-width: 126px; }
.detail-grid .prq-pr { font-size: 0.86rem; margin-top: 0; }
.detail-grid .prq-pr__pct { font-size: 0.76rem; }
/* งานรายรายการ: the item's PR No. sits ABOVE its PO No. in the one column the PO No. already had — a
   second 198px column pushed the table past the card and squeezed item names to a word a line. */
.iw-doc { display: flex; align-items: center; gap: 5px; }
.iw-doc + .iw-doc { margin-top: 4px; }
.iw-doc > span { flex: 0 0 20px; font-size: 0.7rem; font-weight: 600; color: var(--ink-muted); }
.iw-doc > input[type=text] { flex: 1 1 auto; width: 136px; min-width: 0; }
.prq-pr-hint { font-size: 0.7rem; color: var(--warning); margin: 2px 0 2px 25px; overflow-wrap: anywhere; }

/* Overall Work Status — the spine of a request, scrollable sideways on a phone rather than
   squeezed. State is carried by an icon and a word, never by colour alone. */
.wmap__lead { font-size: 0.88rem; margin-bottom: 10px; }
.wmap__row { display: flex; gap: 8px; list-style: none; margin: 0; padding: 0 0 4px; overflow-x: auto; }
.wmap__step {
  flex: 0 0 auto; min-width: 118px; max-width: 168px;
  border: 1px solid var(--border); border-radius: 9px; padding: 8px 10px; background: var(--surface-sunken);
  display: flex; flex-direction: column; gap: 2px; position: relative;
}
.wmap__step + .wmap__step::before {
  content: ""; position: absolute; left: -8px; top: 50%; width: 8px; height: 1px; background: var(--border-strong);
}
.wmap__mark { font-size: 0.9rem; line-height: 1; }
.wmap__label { font-weight: 700; font-size: 0.8rem; color: var(--ink); }
.wmap__who { font-size: 0.74rem; color: var(--ink-muted); overflow-wrap: anywhere; }
.wmap__note { font-size: 0.72rem; color: var(--ink); overflow-wrap: anywhere; }
.wmap__step--done { background: var(--success-surface); border-color: var(--border); }
.wmap__step--done .wmap__mark { color: var(--success); }
/* The ring is drawn INSIDE the box (inset): .wmap__row scrolls sideways, so an outer shadow was clipped on
   the top and left and the ring looked uneven (2026-10-05). 1px border + 1px inset = an even 2px. */
.wmap__step--current { background: var(--warning-surface); border-color: var(--warning-dot); box-shadow: inset 0 0 0 1px var(--warning-dot); }
.wmap__step--wait { opacity: 0.72; }
.wmap__step--skip { opacity: 0.45; }
.scope-note { font-size: 0.75rem; color: var(--ink-muted); margin-top: 2px; overflow-wrap: anywhere; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* The "?" that opens a short explanation next to a filter label. */
.help-dot {
  border: 1px solid var(--border); background: var(--surface); color: var(--ink); border-radius: 50%;
  width: 17px; height: 17px; line-height: 1; font-size: 0.72rem; font-weight: 700;
  cursor: pointer; padding: 0; vertical-align: middle;
}
.help-note { background: var(--surface-sunken); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; margin-top: 10px; font-size: 0.82rem; }
.help-note p { margin: 0 0 6px; }
.help-note p:last-child { margin-bottom: 0; }
.kind-explain { background: var(--surface-sunken); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; margin: 0 0 12px; font-size: 0.85rem; }
.kind-explain .muted { font-size: 0.78rem; margin-top: 4px; }

/* อาจซ้ำ (prq_dup.py): the request page's panel, the new-request form's pre-submit box and the
   list badge. Built on .alert-warn / .badge-age-warn; the secondary text is dark enough to read
   on the amber background (the page-wide .muted grey is not). */
.prq-dup { margin-top: 12px; }
.prq-dup__lead { font-size: 0.95rem; }
.prq-dup__sub { color: var(--warning); font-size: 0.8rem; }
.prq-dup__list { margin: 8px 0; padding-left: 1.2rem; }
.prq-dup__list li { margin-bottom: 8px; }
.prq-dup__row a { color: var(--warning); }
.prq-dup__why { font-size: 0.85rem; margin-top: 2px; }
.prq-dup__form { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 4px; }
.prq-dup__form input[type=text] { flex: 1 1 220px; max-width: 420px; padding: 4px 8px; font-size: 0.85rem; }
.prq-dup__done { margin-top: 6px; }
/* .badge.badge-dup, not .badge-dup: a later bare `.badge` rule would win and turn it grey. */
.badge.badge-dup { background: var(--warning-surface); color: var(--pill-warning); border: 1px solid var(--warning); text-decoration: none; }
.badge.badge-dup:hover { text-decoration: underline; }

/* The floating คำขอ PR helper. Fixed to the corner on desktop; on a phone the panel takes the
   full width above the button, because a 320px card in a corner is unusable there. */
.prqbot-fab {
  position: fixed; right: 18px; bottom: 18px; z-index: 60;
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--brand-600); color: var(--on-brand); border: none; border-radius: 999px;
  padding: 11px 17px; font-size: 0.88rem; font-weight: 600; cursor: pointer;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22);
}
.prqbot-fab:hover { background: var(--brand-700); }
.prqbot {
  position: fixed; right: 18px; bottom: 74px; z-index: 61;
  width: 340px; max-width: calc(100vw - 24px); max-height: min(70vh, 560px);
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18); overflow: hidden;
}
.prqbot__head {
  display: flex; align-items: center; justify-content: space-between;
  background: var(--brand-600); color: var(--on-brand); padding: 9px 12px; font-weight: 600; font-size: 0.88rem;
}
.prqbot__close { background: none; border: none; color: var(--on-brand); font-size: 1.25rem; line-height: 1; cursor: pointer; padding: 0 2px; }
.prqbot__log { padding: 10px 12px; overflow-y: auto; flex: 1; display: flex; flex-direction: column; gap: 7px; }
.prqbot__msg { font-size: 0.83rem; line-height: 1.5; padding: 8px 11px; border-radius: 12px; max-width: 92%; overflow-wrap: anywhere; }
.prqbot__msg--bot { background: var(--track); color: var(--ink); border-bottom-left-radius: 4px; align-self: flex-start; }
.prqbot__msg--me { background: var(--brand-600); color: var(--on-brand); border-bottom-right-radius: 4px; align-self: flex-end; }
.prqbot__cta { align-self: flex-start; text-decoration: none; }
/* An AI fallback answer (2026-09-29): same bubble, a dashed edge, and its warning line under it. */
.prqbot__msg--ai { border: 1px dashed var(--border-strong); }
.prqbot__ainote { margin-top: 6px; padding-top: 5px; border-top: 1px dashed var(--border); font-size: 0.72rem; color: var(--ink-muted); }
.prqbot__chips { display: flex; flex-wrap: wrap; gap: 5px; padding: 0 12px 8px; }
.prqbot__chip {
  background: var(--surface); border: 1px solid var(--border); color: var(--brand-text); border-radius: 999px;
  padding: 5px 10px; font-size: 0.74rem; cursor: pointer;
}
.prqbot__chip:hover { background: var(--surface-hover); }
.prqbot__form { display: flex; gap: 6px; padding: 8px 12px; border-top: 1px solid var(--border); }
.prqbot__form input { flex: 1; min-width: 0; }
.prqbot__foot { margin: 0; padding: 0 12px 10px; font-size: 0.7rem; color: var(--ink-muted); }
/* The FAB is on every signed-in page since 2026-09-27, and a fixed button in the corner sits on top
   of whatever is there — so the page gets room to scroll its last control (a ✓ รับของครบ at the end
   of a table, a form's submit) clear of it. */
@media (max-width: 560px) {
  .prqbot { right: 12px; left: 12px; width: auto; bottom: 68px; max-height: 76vh; }
  .prqbot-fab { right: 12px; bottom: 12px; padding: 10px 14px; }
  .prqbot-fab__txt { display: none; }
}

/* The header card in edit mode, and the field-level history table. */
.detail-edit { margin-top: 4px; }
.prq-audit td { vertical-align: top; }
.audit-old { color: var(--ink-muted); text-decoration: line-through; }
.remark-attach { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 6px 0; }
.remark-attach__btn { cursor: pointer; }
.remark-attach__names { font-size: 0.8rem; }
.remark-files { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; align-items: center; font-size: 0.85rem; }
.chip-assist { background: var(--info-surface); color: var(--pill-info); border-color: var(--border); }

/* --- แผนสั่งซื้อ: Google-sheet rows on the calendar and the /plans page (2026-09-17) --- */
.nav-badge { display: inline-block; min-width: 18px; padding: 0 5px; margin-left: 2px; border-radius: 999px; background: var(--warning-dot); color: var(--on-brand); font-size: 0.72rem; font-weight: 700; line-height: 18px; text-align: center; vertical-align: 1px; }
.cal-item--plan { border: 1px solid var(--warning); background: var(--warning-surface); }
.cal-item--plan b { color: var(--warning); }
.badge-plan { background: var(--warning-surface); color: var(--pill-warning); border: 1px solid var(--warning); }
.badge-auto { background: var(--info-surface); color: var(--pill-info); border: 1px solid var(--border); font-size: 0.7rem; }
.row-plan td { background: var(--warning-surface); }
.plan-status { font-size: 0.78rem; padding: 2px 8px; border-radius: 999px; white-space: nowrap; }
.plan-status--ok { background: var(--track); color: var(--pill-success); }
.plan-status--changed { background: var(--warning-surface); color: var(--pill-warning); }
.plan-status--pending { background: var(--info-surface); color: var(--pill-info); }
.plan-status--unparsed { background: var(--danger-surface); color: var(--pill-danger); }
.plan-status--empty { background: var(--track); color: var(--ink-muted); }
.plan-status--cancelled { background: var(--track); color: var(--ink-muted); text-decoration: line-through; }
.plan-changed { background: var(--warning-surface); }
.plan-cell-raw { color: var(--ink-muted); font-size: 0.78rem; }
/* a grouped screen item (lark_plans.merge_calendar_group): one screen per line */
.plan-group-note { white-space: pre-line; }

/* --- คำขอ PR: master-data picker in the item editor --- */
.item-row__master select { max-width: 100%; }
input.time-24 { max-width: 110px; }

/* ---------- รอมอบหมาย, per-line owners, เคสของฉัน (2026-09-24) ----------
   Phone-first: every tap target here is at least 40px tall, rows are whole-label toggles, and
   nothing needs a horizontal scroll. */
.page-note { color: var(--ink-muted); font-size: 0.86rem; margin: 0 0 12px; }
.section-title--sub { font-size: 1rem; margin-top: 6px; }
.js-only { display: none; }
.has-js .js-only { display: inline-block; }
.q-card .case-head { flex-wrap: wrap; gap: 6px 10px; }
.q-claim { margin: 10px 0 4px; }
.q-claim .btn { min-height: 42px; }
.q-block { margin-top: 10px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface-sunken); }
.q-block > summary { cursor: pointer; padding: 10px 12px; font-weight: 600; font-size: 0.9rem; min-height: 42px; list-style-position: inside; }
.q-block[open] > summary { border-bottom: 1px solid var(--border); }
.q-block > form, .q-block > .line-form, .q-block > .line-empty { padding: 10px 12px; }
.q-form .field { margin-bottom: 10px; }
.q-form .btn { min-height: 40px; }
.q-backlog { margin-top: 18px; }
.q-backlog > summary { cursor: pointer; font-weight: 700; color: var(--ink-muted); padding: 10px 0; min-height: 42px; }
/* รอมอบหมาย / เคสค้างนาน / เคสของฉัน filters + the queue's bulk assign (2026-09-27). A card's
   checkbox joins the bulk bar through form= (queues never nest a form in a card's own forms); the
   anchor jump after an action must clear the sticky header. */
.q-card, .my-card, .q-backlog, #q-fresh { scroll-margin-top: 90px; }
.q-pick { display: inline-flex; align-items: center; justify-content: center; min-width: 36px; min-height: 36px;
  margin: -6px 0 -6px -6px; cursor: pointer; align-self: center; }
.q-pick input { width: 20px; height: 20px; accent-color: var(--primary); cursor: pointer; }
.q-pickall { align-items: center; gap: 6px; font-size: 0.86rem; min-height: 38px; cursor: pointer; }
.has-js .q-pickall.js-only { display: inline-flex; }
.q-pickall input { width: 20px; height: 20px; accent-color: var(--primary); }
.q-due { margin-top: 2px; }
.q-filters { margin-top: 2px; }
/* flex, not the generic .owner-checks grid (165px columns = one column in a phone card). */
.owner-checks--chips { display: flex; flex-wrap: wrap; gap: 8px; }
.owner-checks--chips label { border: 1.5px solid var(--border); border-radius: 999px; padding: 7px 12px; background: var(--surface); min-height: 38px; }
.owner-checks--chips label:has(input:checked) { border-color: var(--primary); background: var(--primary-light); color: var(--brand-text); font-weight: 600; }
.line-list { display: flex; flex-direction: column; gap: 6px; }
.line-row { display: flex; align-items: flex-start; gap: 10px; padding: 9px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); cursor: pointer; min-height: 44px; }
.line-row:has(.line-check:checked) { border-color: var(--primary); background: var(--success-surface); }
.line-row--mine { border-color: var(--brand-600); }
.line-row--done .line-name { color: var(--ink-muted); }
.line-check { width: 20px; height: 20px; margin-top: 2px; flex-shrink: 0; accent-color: var(--primary); }
.line-no { color: var(--ink-muted); font-size: 0.8rem; min-width: 1.4em; margin-top: 2px; }
.line-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.line-name { font-weight: 600; word-break: break-word; }
.line-sub { color: var(--ink-muted); font-size: 0.8rem; }
.line-done { color: var(--success); font-weight: 600; }
.line-owners { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px; }
.line-owners .chip { margin: 0; }
.line-nobody { color: var(--warning); font-size: 0.78rem; }
.chip-me { background: var(--primary); color: var(--on-brand); }
.line-tools { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 4px; }
.line-people { margin-top: 8px; }
.line-people-label { font-size: 0.82rem; color: var(--ink-muted); margin-bottom: 6px; }
.line-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.line-actions .btn { min-height: 40px; }
.line-empty { font-size: 0.85rem; }
@media (max-width: 640px) {
  .line-actions .btn, .q-claim .btn, .q-form .btn { width: 100%; }
}
.my-tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 14px; }
.my-tile { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 12px; text-align: center; color: inherit; text-decoration: none; }
.my-tile--link:hover { border-color: var(--primary); }
.my-tile-n { font-size: 1.5rem; font-weight: 700; color: var(--ink); line-height: 1.2; }
.my-tile-k { font-size: 0.78rem; color: var(--ink-muted); }
.my-card { border: 1px solid var(--border); }
.my-card--ready { border-left-color: var(--primary); }
.my-card--late { border-color: var(--danger); }
.my-card .case-head { flex-wrap: wrap; gap: 6px 8px; }
.chip-role { background: var(--info-surface); color: var(--pill-info); }
/* เคสของฉัน's ช่องทาง (2026-10-14): where a card came from — TRCloud case, Lark Approval, คำขอ PR. */
.chip-ch { font-size: 0.68rem; }
.chip-ch--trcloud { background: var(--success-surface); color: var(--pill-success); }
.chip-ch--approval { background: var(--warning-surface); color: var(--warning); }
.chip-ch--webapp { background: var(--info-surface); color: var(--pill-info); }
.my-tile-sub { font-size: 0.72rem; color: var(--ink-muted); margin-top: 2px; }
.my-progress { display: flex; align-items: center; gap: 8px; font-size: 0.82rem; color: var(--ink-muted); margin-top: 8px; }
.my-bar { flex: 0 0 110px; height: 8px; border-radius: 999px; background: var(--track); overflow: hidden; }
.my-bar > span { display: block; height: 100%; background: var(--primary); }
.my-lines { margin-top: 8px; font-size: 0.86rem; }
.my-lines-head { font-weight: 600; margin-bottom: 2px; }
.my-lines ul { margin: 0; padding-left: 4px; list-style: none; }
.my-lines li { padding: 2px 0; }
.my-lines li > span[aria-hidden] { display: inline-block; width: 1.2em; color: var(--warning); }
.my-lines li.is-done > span[aria-hidden] { color: var(--success); }
.my-lines li.is-done { color: var(--ink-muted); }
.my-card form { margin-top: 10px; display: block; }
@media (max-width: 640px) {
  .my-tiles { gap: 6px; }
  .my-tile { padding: 10px 6px; }
  .my-tile-n { font-size: 1.25rem; }
}
/* Inside a .field the generic `.field label` block rule would stack every chip on its own
   full-width row (9 names = a whole phone screen) — keep them as wrapping chips. */
.field .owner-checks--chips label { display: inline-flex; width: auto; margin: 0; font-size: 0.85rem; font-weight: 500; color: inherit; }
/* Wide screens: a 23-line PR in two columns instead of one very long list. */
@media (min-width: 960px) { .line-list { display: grid; grid-template-columns: 1fr 1fr; } }

/* ---------- บอร์ดทีม 2.1.21 + ✓ รับของแล้ว (2026-09-26) ---------- */
.tb-tabs { display: flex; gap: 6px; overflow-x: auto; margin-bottom: 10px; padding-bottom: 2px; }
.tb-tab { flex: 0 0 auto; padding: 8px 14px; border-radius: 999px; border: 1.5px solid var(--border); background: var(--surface); color: var(--ink); text-decoration: none; font-size: 0.88rem; font-weight: 600; min-height: 38px; display: inline-flex; align-items: center; gap: 6px; }
.tb-tab.is-on { background: var(--primary); border-color: var(--primary); color: var(--on-brand); }
.tb-n { background: rgba(0,0,0,0.08); border-radius: 999px; padding: 0 7px; font-size: 0.78rem; }
.tb-tab.is-on .tb-n { background: rgba(255,255,255,0.25); }
.tb-filters { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 10px; }
.chip-filter { border: 1px solid var(--border); border-radius: 999px; padding: 5px 11px; font-size: 0.8rem; color: var(--ink-muted); text-decoration: none; background: var(--surface); }
.chip-filter.is-on { border-color: var(--primary); background: var(--primary-light); color: var(--brand-text); font-weight: 600; }
.tb-year { margin-left: auto; }
.tb-year select { padding: 5px 8px; border-radius: 8px; border: 1px solid var(--border); }
.tb-bar { display: inline-block; width: 64px; height: 7px; border-radius: 999px; background: var(--track); overflow: hidden; vertical-align: middle; }
.tb-bar > span { display: block; height: 100%; background: var(--primary); }
.tb-prog { white-space: nowrap; }
.badge-received { background: var(--success-surface); color: var(--pill-success); font-weight: 600; }
.row-received td { background: var(--success-surface); }
.btn-link { background: none; border: 0; padding: 0; color: var(--danger); font-size: 0.78rem; text-decoration: underline; cursor: pointer; }
.cal-item--received { background: var(--success-surface); }
.cal-item--received b { color: var(--success); }
.cal-ok { color: var(--success); font-weight: 700; margin-right: 3px; }
.day-round__recv { margin-top: 8px; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.day-round__recv .item-sub { margin: 0; }
.day-round__recv .btn { min-height: 38px; }
.po-state { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 22px; margin: 4px 0 12px; padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface-sunken); }
.po-state__item { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.po-state__item .k { color: var(--ink-muted); font-size: 0.82rem; }
@media (max-width: 640px) { .tb-year { margin-left: 0; } .po-state form, .po-state .btn { width: 100%; } }
.tb-yearnote { font-size: 0.82rem; color: var(--ink-muted); margin: 0 0 8px; }

/* หมายเหตุ of a PO from TRCloud (2026-09-27): verbatim, line breaks kept. */
.po-note { margin: 4px 0 12px; border: 1px solid var(--warning-dot); background: var(--warning-surface); border-radius: 10px; padding: 10px 12px; }
.po-note__head { font-weight: 700; font-size: 0.9rem; color: var(--warning); margin-bottom: 4px; }
.po-note__src { font-weight: 400; color: var(--warning); font-size: 0.78rem; }
.po-note__body { white-space: pre-line; font-size: 0.9rem; line-height: 1.55; color: var(--ink); word-break: break-word; }

/* สถานที่ส่ง settings (2026-09-27) */
.place-rename { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.place-rename input[type="text"] { flex: 1 1 260px; min-width: 0; padding: 7px 10px; border: 1.5px solid var(--border); border-radius: 8px; }
.row-muted td { color: var(--ink-muted); }

/* บอร์ดทีม PR tab: filters, due date, assign dropdown (2026-09-27) */
.tb-prf { display: flex; flex-wrap: wrap; gap: 10px 12px; align-items: flex-end; padding: 12px 14px; margin-bottom: 10px; }
.tb-prf .field { margin: 0; flex: 0 1 160px; }
.tb-prf .tb-prf__q { flex: 1 1 240px; }
.tb-prf .field label { font-size: 0.75rem; margin-bottom: 0.25rem; }
.tb-prf select, .tb-prf input[type="date"], .tb-prf input[type="search"] { width: 100%; padding: 6px 8px; border: 1.5px solid var(--border); border-radius: 8px; font-size: 0.85rem; height: var(--size-control-sm); }
.tb-prf__done { display: flex; align-items: center; gap: 6px; font-size: 0.82rem; min-height: 36px; }
.tb-prf__act { display: flex; gap: 6px; }
.tb-due { font-size: 0.78rem; color: var(--ink-muted); }
.tb-due.is-soon { color: var(--warning); font-weight: 600; }
.tb-due.is-late { color: var(--danger); font-weight: 700; }
.tb-assign select { padding: 5px 8px; border: 1.5px solid var(--border); border-radius: 8px; font-size: 0.84rem; max-width: 190px; }
.tb-assigncell .chip { margin-top: 4px; }
.tb-assign .owner-picker > summary { display: flex; justify-content: space-between; box-sizing: border-box; width: 190px; max-width: 100%;
  min-height: 38px; font-size: 0.9rem; border-color: var(--border-strong); }   /* the picker where the select was */
.tb-assign .owner-picker > summary > span:first-child { overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 640px) { .tb-prf .field { flex: 1 1 45%; } }

/* ---- polish from the 2026-09-27 screenshot check ---- */
/* PR tab on phones: the first column was nowrap (description included) and took the whole card,
   squeezing ผู้ขอ to 53px and breaking สถานะ mid-word. */
.tb-table .td-doc { white-space: normal; min-width: 170px; max-width: 280px; }
.tb-table .td-doc .item-sub { white-space: normal; }
.tb-table .tb-req { min-width: 120px; }
.tb-table .tb-status, .tb-table .tb-duecell { white-space: nowrap; }
.tb-due { white-space: nowrap; }
.tb-assign select { min-height: 38px; font-size: 0.9rem; }
.tb-prf .tb-prf__range { flex: 1 1 280px; }
.tb-prf__range span { display: flex; gap: 6px; }
.tb-prf__range input { flex: 1 1 0; min-width: 0; }
/* สถานที่ส่ง page */
.places-add { margin-top: 12px; }
.places-table .nowrap { white-space: nowrap; }
@media (max-width: 640px) {
  .place-rename input[type="text"] { flex: 1 1 140px; }
  .places-table td { padding-left: 6px; padding-right: 6px; }
}
/* บอร์ดทีม bulk assign (2026-09-27) */
.tb-bulk { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; padding: 10px 14px; margin-bottom: 10px; }
.tb-bulk__count { font-weight: 600; font-size: 0.88rem; color: var(--ink-muted); }
.tb-bulk select { min-height: 38px; padding: 5px 8px; border: 1.5px solid var(--border); border-radius: 8px; font-size: 0.9rem; }
/* These dropdowns are given a border of their own and had no background, so each browser painted its
   own: white in Chromium and Safari, button-grey in Firefox — where the bulk bar's two
   dropdowns, every row's “— เลือกผู้ดูแล —” on บอร์ดทีม and the PO tabs' year all read as disabled
   controls (2026-10-05). White everywhere; scripts/pages_check.py fails on a bordered dropdown that
   is left on the browser's own colour. */
.tb-bulk select, .tb-assign select, .tb-year select { background-color: var(--surface); }
.tb-pick { width: 1%; text-align: center; }
.tb-pick input { width: 20px; height: 20px; accent-color: var(--primary); }
.tb-bulk .btn { min-height: 38px; }

/* ===== บอร์ดทีม: expand a PR row into its lines (2026-09-27) — TRCloud's own row expander ===== */
.tb-exp { border: 0; background: none; padding: 2px 0; margin-top: 4px; cursor: pointer;
  font: inherit; font-size: 0.78rem; font-weight: 600; color: var(--ink); align-items: center; gap: 5px; }
.has-js .tb-exp.js-only { display: flex; width: max-content; }
.tb-exp .exp-sign { display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border: 1px solid var(--border); border-radius: 4px; background: var(--track);
  font-weight: 700; line-height: 1; }
.tb-exp .exp-sign::after { content: "+"; }
.tb-exp.is-open .exp-sign::after { content: "−"; }
.tb-exp:hover, .tb-exp-all:hover { text-decoration: underline; }
.tb-exp-all { margin-left: 6px; border: 1px solid var(--border); background: var(--surface); border-radius: 6px;
  padding: 1px 8px; font: inherit; font-size: 0.72rem; font-weight: 500; color: var(--ink); cursor: pointer; }
.tb-detail > td { background: var(--surface-sunken); padding: 10px 14px 12px 42px; }
.tb-detail__head { display: flex; flex-direction: column; gap: 2px; margin-bottom: 4px; font-size: 0.82rem; }
.tb-detail__note { white-space: pre-line; overflow-wrap: anywhere; }
.tb-detail__empty { margin: 6px 0; font-size: 0.82rem; }
.tb-lines { background: var(--surface); border: 1px solid var(--border); table-layout: fixed; }
/* fixed widths, so stacked PRs line their columns up instead of each table sizing its own */
.tb-lines col.c-no { width: 40px; } .tb-lines col.c-sku { width: 110px; } .tb-lines col.c-money { width: 95px; }
.tb-lines col.c-qty { width: 115px; } .tb-lines col.c-disc { width: 70px; } .tb-lines col.c-own { width: 160px; }
.tb-lines .tb-l-sku { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tb-lines th:last-child, .tb-lines td.tb-l-own { padding-left: 18px; }
.tb-lines tr.is-done td { color: var(--ink-muted); }
.tb-line-done { color: var(--success); font-weight: 600; }
/* Per-line PO links + the ไม่ใช่งานจัดซื้อ action and list (2026-10-02). */
.tb-lines col.c-po { width: 150px; }
.tb-l-polink { display: block; font-size: 0.76rem; font-weight: 500; white-space: nowrap; }
.tb-bulk__or { font-size: 0.82rem; color: var(--ink-muted); }
.chip-filter--aside { border-style: dashed; }
.tb-aside { margin-top: 18px; padding-top: 14px; border-top: 1px dashed var(--border); }
.tb-aside__why { max-width: 360px; white-space: normal; }
@media (max-width: 700px) {
  .tb-l-polink { display: inline; margin-left: 6px; }
}
@media (max-width: 640px) {
  .tb-detail > td { padding-left: 10px; padding-right: 10px; }
  /* The board table is wider than a phone and scrolls sideways; the lines stay pinned to what is
     on screen and scroll inside their own box instead of dragging the whole board along. */
  /* sticky offsets count from inside the card's padding, and the box cannot pass the end of its
     cell: 10px + a width that still fits when the board is scrolled fully right keep it in the
     same place at both ends (measured: 46-344 either way at 390px) */
  .tb-detail__box { position: sticky; left: 10px; width: calc(100vw - 92px); }
  /* each line becomes a small card: product on top, then code · qty · opened as PO · owner —
     nothing to scroll sideways, and money (usually 0 on a PR) left to the desktop view */
  .tb-lines { table-layout: auto; border: 0; background: none; }
  .tb-lines colgroup, .tb-lines tr:first-child, .tb-lines .tb-l-no, .tb-lines .tb-l-money { display: none; }
  .tb-lines tr { display: flex; flex-wrap: wrap; gap: 2px 10px; background: var(--surface); border: 1px solid var(--border);
    border-radius: 8px; padding: 7px 10px; margin-bottom: 6px; }
  .tb-lines td { display: block; border: 0; padding: 0; text-align: left; white-space: normal; }
  .tb-lines .tb-l-name { order: -1; flex-basis: 100%; font-weight: 600; color: var(--ink); }
  .tb-lines tr.is-done .tb-l-name { color: var(--ink-muted); }
  .tb-lines td[data-l]::before { content: attr(data-l) " "; color: var(--ink-muted); font-weight: 400; }
  .tb-lines .tb-l-sku { color: var(--ink); }
}

/* ===== Wide lists inside the sidebar layout (2026-09-27) =====
   The sidebar takes 216px, so the Approval (1142-1532px), คำขอ PR (1498px) and Supplier (1291px)
   tables pushed their last columns - the Approval assign picker among them - off screen at 1366.
   Headers wrap, text columns wrap inside a cap, the picker summary is narrower; badges stay whole.
   The floating owner picker and the @-mention menu sit above the ถามบอท button (z 60). */
.wl-table--wide th { white-space: normal; }
.appr-table .td-doc { white-space: normal; max-width: 150px; }
/* The row's chip on a handler's step names it ("รอคุณดำเนินการ (Handle)", 2026-10-06) — wider than this cell,
   so THAT chip (.badge-await--step) may wrap: between its two parts, each of which stays whole (never inside
   a word). 11px = the round ends a one-line chip has. "รอคุณอนุมัติ" is untouched. */
.appr-table .td-doc .badge-await--step { white-space: normal; border-radius: 11px; }
.badge-await__part { white-space: nowrap; }
.appr-table .td-person { min-width: 110px; max-width: 150px; }
.appr-table .td-owners-chips { min-width: 110px; max-width: 170px; }
.appr-table .td-assign { min-width: 0; }
.appr-table .owner-picker > summary { max-width: 190px; }
.prq-list-table td { white-space: normal; }
.prq-list-table td:first-child { white-space: nowrap; }
.prq-list-table td:nth-child(3) { min-width: 150px; }
.prq-list-table td:nth-child(4) { min-width: 110px; }
.prq-list-table td.td-person { min-width: 100px; max-width: 150px; }
.prq-list-table td:nth-child(7), .prq-list-table td:nth-child(8) { max-width: 165px; }
.prq-list-table td:nth-child(7) .chip { white-space: normal; }
/* คำขอของฉัน (templates/requests.html) has nine columns since 2026-10-12 — the team list's first eight,
   ผู้ขอ among them — and takes the rules above. With the sidebar open on a 1366px laptop its card is
   1070px wide: the two long-text columns give a little there, or the last column leaves the card. */
.prq-reqs-table td:nth-child(3) { min-width: 120px; }
.prq-reqs-table td:nth-child(4) { min-width: 90px; }
.sup-list-table td:first-child { white-space: normal; max-width: 260px; overflow-wrap: anywhere; }
@media (max-width: 1280px) {
  /* laptops: the sidebar is an icon rail here, but the Approval lists still need a little less */
  .appr-table .td-owners-chips { max-width: 125px; }
  .appr-table .owner-picker > summary { max-width: 140px; }
  .appr-table .td-doc { max-width: 120px; }
  .appr-table .td-doc .badge-await--step { padding-left: 6px; padding-right: 6px; }    /* its first part alone fills this narrower cell */
  .appr-table td, .appr-table th { padding-left: 7px; padding-right: 7px; }
  .prq-list-table td:nth-child(3) { min-width: 120px; }
  .prq-list-table td:nth-child(4) { min-width: 90px; }
}

/* ===== บอร์ดทีม: per-line owner chips ✕ + a dropdown per line (Praew, 2026-09-28) ===== */
.tb-lines col.c-own { width: 200px; }
.tb-l-chip { display: inline-flex; align-items: center; gap: 2px; margin: 0 4px 4px 0; }
.tb-l-x { border: 0; background: none; color: var(--danger); cursor: pointer; padding: 0 3px; font-size: 0.8rem; line-height: 1; }
.tb-l-x:hover { color: var(--danger); }
select.tb-l-pick { width: 100%; max-width: 190px; font-size: 0.78rem; padding: 3px 6px; }

/* ===== บอร์ดทีม: per-line owners are STAGED, one บันทึก per PR (Praew, 2026-09-29) ===== */
.tb-l-keep { margin: 0 2px 0 0; vertical-align: -2px; accent-color: var(--primary); }
.has-js .tb-l-keep { display: none; }            /* with JS the ✕ is the control */
.has-js .tb-l-chip label { cursor: default; }
.tb-l-chip.is-new .chip { background: var(--warning-surface); color: var(--pill-warning); outline: 1px dashed var(--warning); outline-offset: -1px; }
.tb-l-own.is-dirty { background: var(--warning-surface); }
/* the save button sits at the right, under the ผู้ดูแลรายการ column it saves (2026-10-09); its notes to the left */
.tb-lsave__bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 6px 10px; margin-top: 8px; padding-right: 9px; }
.tb-lsave__bar [data-line-save-btn] { order: 9; }
.tb-lsave__bar .btn { min-height: 34px; }
.tb-lsave__dirty { font-size: 0.8rem; font-weight: 600; color: var(--warning); }
.tb-lsave__undo { border: 0; background: none; padding: 2px 4px; font: inherit; font-size: 0.8rem;
  color: var(--danger); text-decoration: underline; cursor: pointer; }
.tb-lsave__msg { font-size: 0.8rem; color: var(--ink-muted); overflow-wrap: anywhere; }
.tb-lsave__msg.is-ok { color: var(--success); font-weight: 600; }
.tb-lsave__msg.is-warn { color: var(--warning); }
.tb-lsave__msg.is-err { color: var(--danger); font-weight: 600; }
.tb-lsave.is-busy { opacity: 0.7; }
/* a folded row with unsaved picks: a dot on its [+], drawn OUTSIDE the flow — any text here widened
   the PR-number column on a phone and re-wrapped every row above (a visible jump) */
.tb-exp.has-unsaved .exp-sign { position: relative; border-color: var(--warning); background: var(--warning-surface); }
.tb-exp.has-unsaved .exp-sign::before { content: ""; position: absolute; top: -5px; right: -5px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--warning-dot); box-shadow: 0 0 0 1.5px var(--surface); }

/* ===== Approval: ยกเลิก — ไม่ต้องดำเนินการ (2026-09-30) ===== */
/* .badge.X, not .badge-X: the generic .badge rule sits later in this file and would grey it out. */
.badge.badge-wk-cancelled { background: var(--surface-sunken); color: var(--ink-muted); }
.cancel-reason { margin-top: 3px; font-size: 0.76rem; color: var(--ink-muted); max-width: 260px; white-space: normal;
  overflow-wrap: anywhere; }
.appr-cancel { width: 100%; }
.appr-cancel > summary { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; list-style: none;
  font-size: 0.85rem; color: var(--danger); padding: 6px 10px; border: 1.5px dashed var(--danger); border-radius: 8px; }
.appr-cancel > summary::-webkit-details-marker { display: none; }
.appr-cancel[open] > summary { margin-bottom: 8px; }
.appr-cancel__form { display: flex; flex-direction: column; gap: 8px; max-width: 560px; padding: 10px 12px;
  border: 1px solid var(--danger); border-radius: 10px; background: var(--danger-surface); }
.appr-cancel__form textarea { width: 100%; min-height: 64px; font: inherit; font-size: 0.9rem; padding: 8px 10px;
  border: 1.5px solid var(--border); border-radius: 8px; resize: vertical; }
.appr-cancel__form .inline-actions { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
.appr-cancelled { width: 100%; display: flex; flex-direction: column; gap: 8px; padding: 10px 12px;
  border: 1px solid var(--border-strong); border-radius: 10px; background: var(--surface-sunken); }
.appr-cancelled__reason { font-size: 0.9rem; overflow-wrap: anywhere; white-space: pre-wrap; }
.appr-cancelled__meta { font-size: 0.78rem; color: var(--ink-muted); }
.appr-cancelled form { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
@media (max-width: 640px) {
  .appr-cancel__form .btn, .appr-cancelled form .btn { width: 100%; }
}

/* ===== TRCloud Pipeline on PR / PO lists and the case page (2026-10-02, pr_pipeline.py) =====
   A stage can be a whole sentence ("ยกเลิก PR และแก้ไข PO เก่า (กรณีจำนวน ≤ PR)"), so unlike every other
   badge this one wraps — a nowrap pill that long pushes a phone page sideways. */
.badge.badge-pl { background: var(--info-surface); color: var(--pill-info); white-space: normal; text-align: left;
  border-radius: 10px; line-height: 1.35; max-width: 100%; overflow-wrap: anywhere; }
.badge.badge-pl-warn { background: var(--warning-surface); color: var(--pill-warning); font-weight: 600; }
.tb-pl { margin-top: 4px; white-space: normal; }
.wl-table .td-doc .tb-pl { max-width: 240px; }
.pl-reason { white-space: normal; margin-top: 2px; }
.pl-card { margin: 10px 0 12px; border: 1px solid var(--border); background: var(--brand-050); border-radius: 10px; padding: 10px 12px; }
.pl-card--closed { border-color: var(--danger); background: var(--danger-surface); }
.pl-card__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; font-weight: 700;
  font-size: 0.9rem; color: var(--ink); margin-bottom: 6px; }
.pl-card__link { margin-left: auto; font-weight: 500; font-size: 0.82rem; color: var(--brand-text); }
.pl-card__closed { font-size: 0.86rem; color: var(--danger); margin-bottom: 6px; }
.pl-card__k { font-size: 0.78rem; color: var(--ink-muted); margin: 8px 0 2px; }
/* the log verbatim: the team writes it as lines ("-ส่ง 7/10/69" under each round), so line breaks stay */
.pl-card__log { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 0.9rem; line-height: 1.55;
  color: var(--ink); background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; }
/* PO ที่อาจเปิดแยกจาก PR (2026-10-16, separate_po_hint.py): one block per short line, its POs under it */
.po-hint__list { list-style: none; margin: 8px 0; padding: 0; display: grid; gap: 8px; }
.po-hint__list li { overflow-wrap: anywhere; }

/* ===== คำขอ PR: Hold (2026-10-02, pr_requests.STATUS_HOLD) =====
   Paused, not late: a calm blue-grey with a dashed edge, nothing like the red ค้างนาน mark.
   .badge.badge-wk-hold, not .badge-wk-hold — the bare `.badge` rule above (the neutral default)
   comes after the colour variants and would turn it grey. */
.badge.badge-wk-hold { background: var(--info-surface); color: var(--pill-info); border: 1px dashed var(--border); font-weight: 600; }
/* The reason under the badge in a list cell; the request page's title row hides it (the card has
   its own "เหตุผล" row and the work map says it in the paused box). */
.hold-why { display: block; margin-top: 3px; max-width: 220px; font-size: 0.74rem; line-height: 1.5;
  color: var(--ink-muted); white-space: normal; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.section-title .hold-why { display: none; }
/* Work map: the box the request was paused at. */
.wmap__step--hold { background: var(--brand-050); border: 1px dashed var(--brand-600); }
.wmap__step--hold .wmap__mark, .wmap__step--hold .wmap__note { color: var(--ink); }
.wmap__step--hold .wmap__note { font-weight: 600; }
.wmap__why { margin-top: 3px; font-size: 0.84rem; color: var(--ink); overflow-wrap: anywhere; }
/* The two reason boxes of the work panel (Hold, Cancelled) get two grid columns where there is
   room: a sentence does not fit a 160px cell. Not on a narrow screen — spanning two tracks of a
   one-track grid would add a column and push the page sideways. */
@media (min-width: 900px) {
  .detail-grid > .field[data-status-field="hold"],
  .detail-grid > .field[data-status-field="cancelled"] { grid-column: span 2; }
}

/* ===== Supplier data-source pages (2026-10-04, "click and see the data source") =====
   แดชบอร์ด Supplier's tiles / badges / counts are links now, plus /suppliers/firm and
   /suppliers/claims. Everything is scoped to .sup-* so no other page moves.
   A badge that is a link keeps its family colour: `.wl-table a` (green text) would otherwise win
   over a single-class badge rule and paint the red "ผิดที่ซัพ" chip green. */
.sup-kpi-link { display: inline-flex; align-items: baseline; flex-wrap: wrap; gap: 2px 8px; color: inherit;
  text-decoration: none; border-radius: 6px; }
.sup-kpi-link b { text-decoration: underline; text-decoration-style: dotted; text-decoration-color: var(--ink-subtle);
  text-underline-offset: 3px; }
.sup-kpi-link:hover b, .sup-kpi-link:focus-visible b { text-decoration-style: solid; text-decoration-color: currentColor; }
.sup-kpi-go { font-size: 0.72rem; font-weight: 600; color: var(--ink); white-space: nowrap; }
.sup-rule { margin-top: 6px; padding-top: 6px; border-top: 1px dashed var(--border); color: var(--ink); line-height: 1.5; }
.sup-rule a { color: var(--brand-text); }
/* the tile that carries the counting rule gets two tracks, or the sentence wraps to ten lines */
.kpi-strip > .sup-tile-wide { grid-column: span 2; }
/* a figure that opens its source reads as a link without shouting: dotted underline, solid on hover */
.sup-list-table td a[data-link]:not(.badge) { text-decoration: underline; text-decoration-style: dotted;
  text-decoration-color: var(--ink-muted); text-underline-offset: 3px; }
.sup-list-table td a[data-link]:not(.badge):hover { text-decoration-style: solid; text-decoration-color: currentColor; }
.sup-list-table td:first-child { min-width: 150px; }
a.badge.sup-src { text-decoration: none; cursor: pointer; }
a.badge.sup-src:hover, a.badge.sup-src:focus-visible { text-decoration: underline; }
a.badge.badge-ok.sup-src { color: var(--pill-success); }
a.badge.badge-age-late.sup-src { color: var(--pill-danger); }
.wl-table a.sup-quiet { color: var(--ink-subtle); text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 2px; }
.wl-table a.sup-quiet:hover { color: var(--brand-text); }
.sup-pager { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 8px 14px;
  padding: 12px 0 2px; font-size: 0.84rem; color: var(--ink); }
.sup-facts .item .v a { color: var(--brand-text); }
.sup-facts .item .v .small { font-weight: 400; }
.sup-po-table .num, .sup-contacts-table .num, .sup-claims-by .num { text-align: right; white-space: nowrap; }
.sup-po-table th.num, .sup-contacts-table th.num, .sup-claims-by th.num { text-align: right; }
.sup-total td { background: var(--surface-sunken); border-top: 2px solid var(--border); }
.sup-claims-table td { white-space: normal; }
.sup-claims-table td:first-child { white-space: nowrap; }
.sup-claims-table td:first-child .small { white-space: normal; max-width: 140px; }
.sup-claims-table td:nth-child(3), .sup-claims-table td:nth-child(4) { min-width: 120px; }
.sup-claims-table td:nth-child(5), .sup-claims-table td:nth-child(6) { min-width: 150px; max-width: 240px; }
.sup-claims-table td:nth-child(7) { min-width: 150px; max-width: 220px; }
.sup-claims-table td:nth-child(7) .badge { white-space: normal; }
.sup-claims-table td:nth-child(8) { min-width: 130px; max-width: 200px; overflow-wrap: anywhere; }
.sup-claim-detail { margin-top: 3px; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 3;
  -webkit-box-orient: vertical; overflow: hidden; }
.wl-table .nowrap, .sup-facts .nowrap { white-space: nowrap; }
@media (max-width: 640px) {
  /* Phone: a claim is a card, on the SAME <tr>/<td> (labels from data-label) — eight columns do
     not fit 390px and sideways scrolling hides the verdict, which is the point of the page. */
  .sup-claims-table { min-width: 0; display: block; }
  .sup-claims-table tbody { display: block; }
  .sup-claims-table tr { display: block; padding: 10px 2px; border-bottom: 1px solid var(--border); }
  .sup-claims-table tr:first-child { display: none; }
  .sup-claims-table td { display: block; border: 0; padding: 2px 0; min-width: 0 !important; max-width: none !important; }
  .sup-claims-table td[data-label]::before { content: attr(data-label); display: block; font-size: 0.7rem;
    color: var(--ink-muted); margin-top: 4px; }
  .sup-claims-table td:first-child { font-size: 1rem; white-space: normal; }
  .sup-claims-table td:first-child .small { max-width: none; }
  .sup-claims-table td:first-child::before { display: none; }
  .sup-claims-table td.empty-cell { text-align: center; }
  .sup-po-table, .sup-contacts-table, .sup-claims-by { min-width: 0; }
  .sup-po-table th, .sup-po-table td, .sup-contacts-table th, .sup-contacts-table td,
  .sup-claims-by th, .sup-claims-by td { padding: 7px 6px; font-size: 0.82rem; }
  .sup-po-table td.td-doc, .sup-contacts-table td.td-doc { white-space: normal; overflow-wrap: anywhere; }
  .sup-facts { grid-template-columns: 1fr 1fr; }
  .sup-kpi-go { white-space: normal; }
}

/* ===== Bulk bar: เปลี่ยนสถานะ (2026-10-04 — case_moves.py, templates/_list_tools.html bulk_bar) =====
   The bar's second action on the ticked rows: หรือ [เปลี่ยนสถานะเป็น… ▾] [เหตุผล] [เปลี่ยนสถานะ].
   It replaced the 2026-10-02 ไม่ใช่งานจัดซื้อ button (.tb-bulk__aside / .tb-bulk__asidebtn above are no
   longer rendered). Divided from the assign controls on a wide screen, on its own row on a phone. */
.tb-bulk__status { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; min-width: 0;
  padding-left: 12px; margin-left: 4px; border-left: 1px solid var(--border); flex: 1 1 360px; }
.tb-bulk__status select { max-width: 100%; }
/* The reason box takes what is left of the row and may get narrow, so the button stays on that row. */
.tb-bulk__status input[type="text"] { min-height: 38px; min-width: 120px; padding: 5px 10px; border: 1.5px solid var(--border);
  border-radius: 8px; font-size: 0.9rem; flex: 1 1 150px; max-width: 360px; }
/* A status move takes rows off the list and (close / cancel) cannot be undone here: not the primary green. */
/* red like production: the status menu holds ยกเลิก / ปิด / ไม่ใช่งานจัดซื้อ. Two classes, so one-platform.css's
   later .btn-outline (blue) cannot win again (it did from 2026-10-05 to 10-09) */
.btn-outline.tb-bulk__statusbtn { border-color: var(--danger); color: var(--danger); }
.btn-outline.tb-bulk__statusbtn:hover { background: var(--danger-surface); }
/* The reason box shows only while the chosen move needs one — :has(), no script (2026-10-06: the JS
   fallback for browsers without :has() went; every browser the team uses has had it since 2023). */
.tb-bulk__status:has([data-bulk-move]):not(:has(option[data-reason]:checked)) [data-bulk-reason] { display: none; }
@media (max-width: 700px) {
  .tb-bulk__status { padding-left: 0; margin-left: 0; border-left: 0; flex-basis: 100%; }
  /* Phone: every control of the bar is a 40px+ target, none wider than the bar, and 16px text so
     iOS does not zoom the page when one is focused. */
  .tb-bulk select, .tb-bulk .btn, .tb-bulk input[type="text"], .tb-bulk .q-pickall { min-height: 42px; }
  .tb-bulk select, .tb-bulk input[type="text"] { font-size: 16px; min-width: 0; max-width: 100%; }
  .tb-bulk > select { flex: 1 1 180px; }
  .tb-bulk__status select, .tb-bulk__status input[type="text"] { flex: 1 1 100%; max-width: none; }
  .tb-bulk__statusbtn { flex: 1 1 auto; }
}

/* ===== Approval: one press — ✓ อนุมัติ / ✕ ไม่อนุมัติ + ผู้ดูแลงาน + ยืนยันข้อมูล (2026-10-04) =====
   templates/_approval_act.html + static/approval-act.js. The block is the LAST cell of a list row
   (td.td-act) and the Lark card / ผู้ดูแลงาน card of the detail page.
   Buttons are real buttons, at least 40px tall everywhere (44px on a phone), one colour each:
   green = approve, red outline = reject, the app's primary green = มอบหมาย + ยืนยัน.
   The list is a wide table inside a sideways scroller, so the action cell is pinned to the scroller's
   right edge (position: sticky): the buttons stay in reach at any width, with nothing to scroll for.
   Sticky cells are their own stacking contexts — the one being used is lifted above its neighbours
   (open picker, open question), or the rows below would paint over its popover. */
.apr-act { display: flex; flex-direction: column; align-items: stretch; gap: 6px; min-width: 0; }
.apr-act .owner-picker > summary { width: 100%; max-width: none; justify-content: space-between; min-height: 36px; }
.apr-act .owner-picker > summary > span:first-child { overflow: hidden; text-overflow: ellipsis; }
.apr-act__btns { display: flex; flex-wrap: wrap; gap: 4px; }
.page-content .apr-act__btn { min-height: 40px; padding: 8px 9px; font-size: 0.88rem; border-radius: 9px;
  border: 2px solid transparent; flex: 1 1 auto; }
.page-content .apr-act__btn--approve { background: var(--success-solid); color: var(--on-brand); }
.page-content .apr-act__btn--approve:hover { background: var(--success); }
.page-content .apr-act__btn--reject { color: var(--danger); border-color: var(--danger); background: var(--surface); }
.page-content .apr-act__btn--reject:hover { background: var(--danger-bg); }
.page-content .apr-act__btn--rejectgo { background: var(--danger-solid); color: var(--on-brand); }
.page-content .apr-act__btn--rejectgo:hover { background: var(--danger-solid); }
.page-content .apr-act__btn--assign { background: var(--primary); color: var(--on-brand); }
/* the same press on a job that is already released (กำลังดำเนินการ): only a change of names needs it */
.page-content .apr-act__btn--quiet { background: var(--surface); color: var(--brand-text); border-color: var(--primary); }
.page-content .apr-act__btn--quiet:hover { background: var(--primary-light); }
.page-content .apr-act__btn--no { color: var(--ink); border-color: var(--border); background: var(--surface); flex: 0 0 auto; }
.apr-act [disabled] { opacity: 0.6; cursor: progress; }
.apr-act[aria-busy="true"] .owner-picker > summary, form[data-apr-act][aria-busy="true"] .owner-picker > summary {
  pointer-events: none; opacity: 0.6; }
/* the question before a Lark decision, in place of the buttons */
.apr-act__ask { display: flex; flex-direction: column; gap: 6px; padding: 8px 10px; border-radius: 10px;
  background: var(--warning-surface); border: 1.5px solid var(--warning); }
.apr-act__q { margin: 0; font-size: 0.86rem; font-weight: 600; color: var(--warning); line-height: 1.45; white-space: normal;
  overflow-wrap: anywhere; }
.apr-act__why { display: flex; flex-direction: column; gap: 3px; font-size: 0.78rem; color: var(--warning); }
.apr-act__why textarea { width: 100%; min-height: 3.4em; resize: vertical; font: inherit; font-size: 16px; padding: 6px 8px;
  border: 1.5px solid var(--border); border-radius: 8px; background: var(--surface); }
.apr-act__askbtns { display: flex; flex-wrap: wrap; gap: 6px; }
/* what happened, next to what changed */
.apr-act__msg { font-size: 0.82rem; line-height: 1.45; white-space: normal; overflow-wrap: anywhere; border-radius: 8px; }
.apr-act__msg:empty { display: none; }
.apr-act__msg.is-ok { color: var(--success); background: var(--primary-light); padding: 6px 9px; font-weight: 600; }
.apr-act__msg.is-warn { color: var(--warning); background: var(--warning-surface); padding: 6px 9px; font-weight: 600; }
.apr-act__msg.is-err { color: var(--danger); background: var(--danger-bg); padding: 6px 9px; font-weight: 600; }
.apr-act__msg.is-busy { color: var(--ink-muted); }
.apr-act__msg:focus { outline: none; }
.apr-act__sign { font-size: 0.78rem; color: var(--danger); white-space: normal; }
/* Whose turn it is (2026-10-05, _approval_act.html turn_line): a few words beside the action block —
   above the row's picker, as the first line of the Lark card on the Approval page, or under the status
   badge on a list with no action column. Text only; it wraps inside whatever holds it, so the pinned
   column keeps its width. Amber = Lark waits on someone else and the reader's own step is still to
   come; plain = only who Lark waits for; green = the reader has done their step. */
.apr-turn { display: flex; flex-direction: column; gap: 2px; margin: 0 0 6px; font-size: 0.78rem; line-height: 1.4;
  font-weight: 500; color: var(--ink-muted); white-space: normal; overflow-wrap: anywhere; text-align: left; }
.apr-turn b { font-weight: 700; color: var(--ink); }
.apr-turn--before { padding: 6px 8px; border-radius: 8px; background: var(--warning-surface); border: 1px solid var(--warning-dot); color: var(--warning); }
.apr-turn--before b { color: var(--warning); }
.apr-turn--before .apr-turn__who { font-weight: 600; }
.apr-turn--decided .apr-turn__me { color: var(--primary-dark); font-weight: 700; }
.apr-turn--mine { color: var(--warning); }
/* the reader's own request, sent back: they re-submit in Lark — said in the amber of a thing to do */
.apr-turn--resubmit { padding: 6px 8px; border-radius: 8px; background: var(--warning-surface); border: 1px solid var(--warning-dot); color: var(--warning); }
.apr-turn--resubmit .apr-turn__me { font-weight: 700; }
.apr-turn__go { font-weight: 600; color: var(--primary); }
td > .apr-turn:last-child { margin-bottom: 0; }
/* under the status badge (a list without the action column) */
.appr-table td:not(.td-act) > .apr-turn { margin: 4px 0 0; min-width: 150px; max-width: 220px; }
/* under มอบหมาย + ยืนยัน pressed before the reader's own step: what the press is not */
.apr-act__later { font-size: 0.76rem; line-height: 1.35; color: var(--ink-muted); white-space: normal; }
.apr-act--wide .apr-act__later { flex: 1 1 100%; }
/* the Lark card of the Approval page: the turn line is the card's first line, at reading size */
.lark-open > .apr-turn { font-size: 0.92rem; margin-bottom: 10px; }
.lark-open > .apr-turn--other .apr-turn__who, .lark-open > .apr-turn--before .apr-turn__who,
.lark-open > .apr-turn--decided .apr-turn__me { font-weight: 700; }
.lark-open > .apr-turn--other { color: var(--ink); }
.lark-open--mine > .apr-turn { margin: -4px 0 8px; font-size: 0.86rem; }
/* รอฉันอนุมัติ: the tab reads as a call while something waits; the sidebar's badge is the same number */
.tab.tab--await .tab-count { background: var(--warning-surface); color: var(--warning); }
.tab.tab--await.active .tab-count { background: var(--warning); color: var(--surface); }
/* What each situation on a row means (act_help): up to three small cards under the list — when · the
   button · what the press does. */
.apr-help { margin-top: 12px; padding: 12px 14px; }
.apr-help__title { font-size: 0.86rem; font-weight: 700; color: var(--ink); margin-bottom: 8px; }
.apr-help__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 8px; }
.apr-help__case { display: flex; flex-direction: column; gap: 3px; padding: 9px 11px; border-radius: 10px;
  background: var(--surface-sunken); border: 1px solid var(--border); font-size: 0.84rem; line-height: 1.45; }
.apr-help__case--mine { border-color: var(--warning-dot); background: var(--warning-surface); }
.apr-help__case--wait { border-color: var(--border-strong); }
.apr-help__case--staged { border-color: var(--brand-600); }
.apr-help__when { font-weight: 600; color: var(--ink-muted); }
.apr-help__btn { color: var(--ink); }
.apr-help__does { color: var(--ink-muted); }
.apr-help__more { margin-top: 8px; font-size: 0.8rem; color: var(--ink-muted); }
.apr-help__more summary { cursor: pointer; color: var(--primary); font-weight: 600; }
.apr-help__more ul { margin: 6px 0 0; padding-left: 18px; display: grid; gap: 4px; }
/* list: the pinned action column. A fixed 204px — the width the picker alone had — so the nine columns of
   กำลังดำเนินการ still fit a 1366px screen. The open question needs more: it reaches 76px over the column
   on its left (this row only) instead of widening its own, so no other row re-wraps while it is open. */
.appr-table .td-act { width: 204px; min-width: 204px; max-width: 204px; white-space: normal; }
.appr-table td.td-act .apr-act__ask { margin-left: -76px; box-shadow: 0 6px 18px rgba(0,0,0,.14); }
.appr-table th.th-act, .appr-table td.td-act { position: sticky; right: 0; z-index: 2; background: var(--surface);
  border-left: 1px solid var(--border); }
.appr-table th.th-act { background: var(--surface-sunken); }
.appr-table tr.wl-row-overdue > td.td-act { background: var(--danger-surface); }
.appr-table tr.wl-row-due > td.td-act { background: var(--warning-surface); }
.appr-table td.td-act:focus-within, .appr-table td.td-act:has(details[open]) { z-index: 6; }
.appr-table td.td-act.is-asking { z-index: 75; }
.appr-table tr.apr-row-flash > td { animation: apr-row-flash 1.6s ease-out 1; }
@keyframes apr-row-flash { from { background-color: var(--success-surface); } }
/* a row that left this tab: one line in its place, kept as tall as the row was (nothing below moves) and
   pinned to the visible part of the scroller, however wide the table is */
.appr-table tr.apr-row-gone > td { background: var(--surface-sunken); vertical-align: middle; }
.appr-table tr.apr-row-gone .apr-act__msg { display: inline-block; position: sticky; left: 0;
  max-width: min(100%, calc(100vw - 4.5rem)); }
/* detail page */
.apr-act--wide { flex-direction: row; flex-wrap: wrap; align-items: flex-start; gap: 8px 10px; }
.apr-act--wide .owner-picker { flex: 0 1 320px; min-width: 200px; }
.apr-act--wide .apr-act__btns { flex: 0 0 auto; }
.apr-act--wide .apr-act__msg { flex: 1 1 100%; }
.apr-act__owners { display: flex; flex-direction: column; gap: 4px; max-width: 420px; }
.lark-decide .owner-picker > summary { width: 100%; max-width: none; justify-content: space-between; min-height: 40px; }
.lark-decide .apr-act__ask { max-width: 560px; }
.lark-decide .apr-act__btn { flex: 0 0 auto; padding: 10px 24px; font-size: 1rem; }
.page-content .lark-decide .apr-act__btn--approve { background: var(--success-solid); color: var(--on-brand); }
.apr-flash { margin: 12px 0 0; padding: 10px 14px; border-radius: 10px; font-size: 0.92rem; font-weight: 600; line-height: 1.5;
  overflow-wrap: anywhere; scroll-margin-top: 90px; }
.apr-flash.is-ok { color: var(--success); background: var(--primary-light); border: 1px solid var(--success); }
.apr-flash.is-warn { color: var(--warning); background: var(--warning-surface); border: 1px solid var(--warning); }
.apr-flash.is-err { color: var(--danger); background: var(--danger-bg); border: 1px solid var(--danger); }
.apr-flash:focus { outline: none; }
.apr-sync { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin: 8px 2px 0; }
.apr-sync__at { font-size: 0.8rem; color: var(--ink-muted); }
/* the live blocks are wrappers for the script only: they must not change the page's own layout */
[data-apr-live] { display: contents; }
.page-content > [data-apr-live] > .section-title { margin: 1.5rem 0 0.7rem; font-size: 1rem; }
@media (max-width: 640px) {
  .page-content .apr-act__btn { min-height: 44px; }
  /* a narrow pinned column: the picker over two stacked buttons, the serial number still visible beside it.
     ::after carries the cell's own background across the card's right padding, where the cells scrolled
     underneath would otherwise show through as slivers of text. */
  .appr-table .td-act { width: 132px; min-width: 132px; max-width: 132px; padding-left: 6px; padding-right: 6px; }
  .appr-table td.td-act .apr-act__ask { margin-left: 0; }
  .appr-table th.th-act::after, .appr-table td.td-act::after { content: ""; position: absolute; top: 0; bottom: 0;
    left: 100%; width: 1.25rem; background: inherit; }
  .appr-table .td-act .apr-act__btns { flex-direction: column; }
  .appr-table .td-act .owner-picker > summary { font-size: 0.8rem; padding: 6px 8px; min-height: 40px; }
  .appr-table .td-act .apr-act__btn { padding: 8px 6px; font-size: 0.86rem; }
  /* "มอบหมาย + ยืนยัน" is wider than the column on one line (131px in 120px — its right edge ran under the
     card's padding): the label wraps instead, the button stays inside its cell */
  .appr-table .td-act .apr-act__btn { white-space: normal; min-width: 0; overflow-wrap: anywhere; line-height: 1.25; }
  /* the turn line in the 132px column: smaller, tighter — the column's width does not change */
  .appr-table .td-act .apr-turn { font-size: 0.72rem; line-height: 1.35; }
  .appr-table .td-act .apr-turn--before, .appr-table .td-act .apr-turn--resubmit { padding: 5px 6px; }
  .appr-table .td-act .apr-act__later { font-size: 0.7rem; }
  /* the question does not fit a 132px column: it opens as a sheet along the bottom of the screen */
  .appr-table .td-act .apr-act__ask { position: fixed; left: 8px; right: 8px; bottom: 8px; z-index: 5; padding: 12px;
    box-shadow: 0 10px 30px rgba(0,0,0,.28); max-height: 70vh; overflow-y: auto; }
  .appr-table .td-act .apr-act__askbtns .apr-act__btn { flex: 1 1 0; }
  .apr-act--wide .owner-picker { flex: 1 1 100%; }
  .apr-act--wide .apr-act__btns, .apr-act--wide .apr-act__btn { width: 100%; }
  .lark-decide .lark-open__actions .apr-act__btn, .lark-decide .lark-decide__btn { flex: 1 1 40%; }
  .apr-sync .btn { min-height: 40px; }
}

/* ===== The case page, read at a glance (2026-10-05, templates/case_detail.html) =====
   A summary band, then a side panel (who has it, what's next, the latest history) beside the main
   column. DOM order is the phone order; from 1024px the side panel sits on the right and stays in
   view, scrolling inside itself when it is taller than the screen. */
.cd-band__top { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.cd-band__pills { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.cd-band__ref { display: inline-flex; align-items: center; font-weight: 700; color: var(--ink); }   /* คำขอ PR's number + its copy button */
.cd-band__act { margin-left: auto; display: flex; align-items: center; gap: var(--space-2); }
.cd-band__act .q-claim { margin: 0; }
.cd-band .cd-what { margin: var(--space-3) 0 0; font-size: 1.05rem; font-weight: 600; color: var(--ink); }
.cd-band > .appr-cancelled, .cd-band > .cd-steps, .cd-band > .cd-facts { margin-top: var(--space-4); }
.cd-band > .cd-facts { margin-bottom: 0; }
.cd-steps .wmap__step { flex: 1 1 0; min-width: 0; max-width: none; flex-direction: row; align-items: center;
  flex-wrap: wrap; gap: 2px var(--space-2); padding: var(--space-2) var(--space-3); }
.cd-steps .wmap__who { flex-basis: 100%; }

.cd-cols { display: flex; flex-direction: column; gap: var(--space-4); margin-top: var(--space-4); }
.cd-side { display: contents; }          /* phone: who → main → info, history (order below) */
.cd-who { order: 1; } .cd-main { order: 2; min-width: 0; } .cd-hist { order: 3; } .cd-info { order: 4; }
.cd-main > .section-title { margin: var(--space-6) 0 var(--space-2); }
.cd-main > :first-child { margin-top: 0; }
.cd-main > .pl-card { margin: 0 0 var(--space-4); }

.cd-h { font-size: 0.82rem; font-weight: 600; color: var(--ink-muted); margin-bottom: var(--space-1); }
.cd-owner { font-size: 1.15rem; font-weight: 700; color: var(--ink); line-height: 1.3; }
.cd-owner--none { color: var(--warning); }
.cd-role { font-size: 0.8rem; color: var(--ink-muted); }
.cd-co { margin-top: var(--space-2); display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); }
.cd-co .cd-role { margin-right: var(--space-1); }
.cd-lines-sum { display: block; margin-top: var(--space-3); font-size: 0.88rem; color: var(--brand-text); }
.cd-lines-sum--warn { color: var(--warning); font-weight: 600; }
.cd-who .q-claim { margin: var(--space-3) 0 0; }
.cd-assign { margin-top: var(--space-3); scroll-margin-top: calc(var(--hdr-h) + var(--space-4)); }
.cd-assign > summary { list-style: none; }
.cd-assign > summary::-webkit-details-marker { display: none; }
.cd-assign__form { display: flex; flex-direction: column; gap: var(--space-3); margin-top: var(--space-3);
  padding: var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface-sunken); }
.cd-assign__form .field { margin: 0; }
.cd-assign__form .btn { align-self: flex-start; }
.cd-next { margin-top: var(--space-4); padding-top: var(--space-3); border-top: 1px solid var(--border);
  font-size: 0.92rem; color: var(--ink); }
/* ผู้ขาย → the vendor registry as a floating card: hover, focus, or .is-open (a tap, case_detail's script).
   The card starts at the name's bottom edge with a padding bridge, so the pointer can travel into it. */
.cd-vendor { position: relative; display: inline-block; }
.cd-vendor__btn { padding: 0; border: 0; background: none; font: inherit; font-weight: 600; color: var(--ink);
  text-align: left; cursor: pointer; text-decoration: underline dotted var(--border-strong); text-underline-offset: 4px; }
.cd-vendor__i { font-size: 0.85em; color: var(--ink-muted); }
.cd-vpop { display: none; position: absolute; left: 0; top: 100%; z-index: 30; width: max-content; max-width: min(360px, calc(100vw - 2rem));
  padding: var(--space-3) var(--space-4); margin-top: var(--space-2); flex-direction: column; gap: var(--space-2);
  background: var(--surface-overlay); border: 1px solid var(--border); border-radius: var(--radius-md); box-shadow: var(--shadow-card);
  font-size: 0.88rem; font-weight: 400; }
.cd-vpop::before { content: ""; position: absolute; left: 0; right: 0; top: calc(-1 * var(--space-2)); height: var(--space-2); }
.cd-vendor:hover .cd-vpop, .cd-vendor:focus-within .cd-vpop, .cd-vendor.is-open .cd-vpop { display: flex; }
.cd-vpop__head { font-weight: 600; color: var(--ink); }
.cd-vpop__head a { color: var(--brand-text); }
.cd-vpop__row { display: flex; flex-direction: column; }
.cd-vpop__row .k { color: var(--ink-muted); font-size: 0.82rem; }
.cd-vpop__row .v { color: var(--ink); font-weight: 600; overflow-wrap: break-word; }
.cd-hist .timeline { margin: 0; }
.cd-hist__more { margin-top: var(--space-2); }

.cd-items .cd-line--done td { color: var(--ink-muted); }
.cd-items .chip { margin: 1px 0; }
.cd-lines-edit > summary { list-style: none; }
.cd-lines-edit > summary::-webkit-details-marker { display: none; }
.cd-lines-edit[open] > summary { margin-bottom: var(--space-3); }
/* while the per-item editor is open it replaces the table (it lists the same lines, with boxes) */
.cd-items:has(> .cd-lines-edit[open]) > .wl-table-wrap { display: none; }

/* ⋯ — everything rare or destructive, out of the daily path. A <details> popover: works without JS. */
.cd-menu { position: relative; }
.cd-menu > summary { list-style: none; min-width: var(--size-control-sm); justify-content: center; font-size: 1.1rem; letter-spacing: 1px; }
.cd-menu > summary::-webkit-details-marker { display: none; }
.cd-menu__pop { position: absolute; right: 0; top: calc(100% + var(--space-1)); z-index: 30; min-width: 240px;
  max-width: min(380px, calc(100vw - 2rem)); padding: var(--space-1); background: var(--surface-overlay);
  border: 1px solid var(--border); border-radius: var(--radius-md); box-shadow: var(--shadow-card); }
.cd-menu__item { display: flex; align-items: center; width: 100%; min-height: var(--size-tap); padding: 0 var(--space-3);
  border: 0; border-radius: var(--radius-sm); background: none; color: var(--brand-text); font: inherit; font-size: 0.92rem;
  text-align: left; text-decoration: none; cursor: pointer; list-style: none; }
.cd-menu__item::-webkit-details-marker { display: none; }
.cd-menu__item:hover { background: var(--surface-hover); }
.cd-menu__item--danger { color: var(--danger); }
.cd-menu__sep { border: 0; border-top: 1px solid var(--border); margin: var(--space-1) 0; }
.cd-menu form { display: block; margin: 0; }
.cd-menu .appr-cancel > summary { display: flex; border: 0; padding: 0 var(--space-3); font-size: 0.92rem; }
.cd-menu .appr-cancel[open] > summary { margin-bottom: 0; }
.cd-menu .appr-cancel__form { margin: var(--space-1) var(--space-2) var(--space-2); }
.cd-menu .cd-menu__form { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-2) var(--space-3) var(--space-3);
  min-width: 260px; }   /* .cd-menu form (display: block) used to outrank it: no gap, a cramped stack */
/* its select (เปลี่ยนหมวด…) drawn like the app's other boxes, not the browser's 13px default, with the save
   button full width under it (the user, 2026-10-09: "not correctly placed") */
.cd-menu__form select { box-sizing: border-box; width: 100%; height: var(--size-control-sm); padding: 0 0.8rem;
  border: 1.5px solid var(--border-strong); border-radius: var(--radius-md); background: var(--surface); color: var(--ink);
  font: inherit; font-size: 0.92rem; }
.cd-menu__form .btn { width: 100%; justify-content: center; }

@media (min-width: 1024px) {
  .cd-cols { display: grid; grid-template-columns: minmax(0, 1fr) 340px; grid-template-areas: "main side"; align-items: start; }
  .cd-main { grid-area: main; }
  /* Only the ผู้ดูแล card (the actions + ขั้นต่อไป) stays pinned below the top bar; the cards under it
     (ประวัติล่าสุด, ข้อมูลอื่น) scroll with the page and pass beneath it (the user, 2026-10-09: the whole
     column used to stick and scroll inside itself once a long history made it taller than the screen). */
  .cd-side { grid-area: side; display: flex; flex-direction: column; gap: var(--space-4); align-self: stretch; }
  .cd-side > .cd-who { position: sticky; top: calc(var(--hdr-h) + var(--space-4)); z-index: 3; }
}
@media (max-width: 640px) {
  /* the ⋯ stays at the right edge (its popover opens leftwards from there); only a row that carries a
     main action takes the full width, the action filling what the ⋯ leaves */
  .cd-band__act:has(> :not(.cd-menu)) { width: 100%; margin-left: 0; }
  .cd-band__act > :first-child:not(.cd-menu) { flex: 1; }
  .cd-band__act > :first-child:not(.cd-menu) .btn, .cd-band__act > a.btn { width: 100%; }
  .cd-steps .wmap__step { flex: 0 0 auto; min-width: 118px; }
  .cd-band > .cd-facts { grid-template-columns: 1fr 1fr; }
  .cd-vpop { max-width: calc(100vw - 4rem); }
}
/* คำขอ PR on the case skeleton (2026-10-05) */
.cd-band .cd-wmap { margin-top: var(--space-3); }
.cd-band .cd-wmap .wmap__lead { margin-bottom: var(--space-2); }
.cd-who__edit { margin-top: var(--space-3); }
.cd-info .cd-kv .item .v { font-size: 0.9rem; }
.prq-empty-fields { margin-top: var(--space-2); }
.cd-kv { grid-template-columns: 1fr; gap: var(--space-2); margin-bottom: 0; }
.cd-kv .item { display: grid; grid-template-columns: 42% minmax(0, 1fr); gap: var(--space-2); align-items: baseline; }

/* ── The iOS-safe date input (templates/_date_field.html, static/date-field.js; One Platform 2026-10-08) ──
   A box that shows the date, with the real <input type="date"> laid over it at opacity 0: on an iPhone
   the native control is drawn at a width CSS cannot shrink and pushed out of its card. The input's size
   comes from its offsets alone, so its content never reaches the layout; it stays on top, so a tap opens
   the phone's own picker. The box copies the field it replaces in each place: a form field (.field), a
   filter row (.form-inline) and the list filters (.tb-prf). Fallbacks for the supplier portal, which
   loads no tokens. */
.date-field { position: relative; display: block; flex: 1 1 0; min-width: 0; }
.date-display {
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; box-sizing: border-box;
  width: 100%; min-height: var(--size-control-sm, 40px); padding: 0 0.8rem; overflow: hidden; white-space: nowrap;
  border: 1.5px solid var(--border-strong, #c7ccd4); border-radius: var(--radius-md, 12px);
  background: var(--surface, #fff); color: var(--ink, #1a1f29); font: inherit;
}
.date-display.is-empty { color: var(--ink-subtle, #6b7280); }
/* the calendar mark, a mask so it takes the text colour in both themes */
.date-display::after {
  content: ""; flex: none; width: 1.05rem; height: 1.05rem; background: currentColor; opacity: 0.7;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.5' y='5' width='17' height='15.5' rx='2.5'/%3E%3Cpath d='M3.5 10h17M8 3v4M16 3v4'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.5' y='5' width='17' height='15.5' rx='2.5'/%3E%3Cpath d='M3.5 10h17M8 3v4M16 3v4'/%3E%3C/svg%3E") center / contain no-repeat;
}
/* focus is one ring (One Platform): drawn on the box, since the input itself is invisible */
.date-field:has(.date-native-input:focus-visible) .date-display { outline: 2px solid var(--focus-ring, #2563eb); outline-offset: 2px; }
.date-field > input.date-native-input {
  position: absolute; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%; min-width: 0;
  margin: 0; padding: 0; border: 0; opacity: 0; font-size: 16px; cursor: pointer;   /* 16px: iOS zooms into a smaller field */
}
.field .date-display { min-height: var(--size-tap); padding: 0 0.8rem; font-size: 0.95rem; }
.form-inline .date-display { min-height: var(--size-control-sm, 40px); padding: 0 0.8rem; font-size: 0.92rem; }
.tb-prf .date-display { min-height: var(--size-control-sm, 40px); padding: 6px 8px; font-size: 0.85rem; }

/* ── งานรายคน: the compact case card (templates/board.html, 2026-10-08) ── number + day chip, status +
   Pipeline mark; "รายละเอียด ›" folds the supplier, category, co-owners and the items (unfolded inside). */
.case-card .status-row { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
/* the › sits in front of the number: the summary is placed over the card's left gutter, so a closed fold
   takes no row of its own */
.case-card { position: relative; padding-left: 30px; }
.case-card .doc > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* status + Pipeline share a line when they fit; else the mark takes a third line (3 rows at most). A long
   Pipeline stage is cut to one line — the tooltip has it whole. */
.case-card .status-row > .badge { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cc-more > summary { position: absolute; top: 6px; left: 4px; display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 6px; list-style: none; cursor: pointer; color: var(--ink-muted); }
.cc-more > summary::-webkit-details-marker { display: none; }
.cc-more > summary:hover { color: var(--brand-text); background: var(--surface-hover); }
.cc-more > summary:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 0; }
.cc-more__chev { display: inline-flex; transition: transform 120ms ease; }
.cc-more[open] .cc-more__chev { transform: rotate(90deg); }
.cc-more[open] { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border); }
.cc-more > .meta { margin-top: 0; }
.cc-more__co { margin-top: 4px; }
.items-head { margin: 6px 0 0; font-size: 0.76rem; font-weight: 600; color: var(--ink-muted); }
/* a long column: the cards after the first six fold behind one full-width button (board.html) */
.col-more > summary { display: flex; align-items: center; justify-content: center; min-height: var(--size-tap); list-style: none;
  cursor: pointer; border: 1.5px dashed var(--border-strong); border-radius: 10px; background: var(--surface);
  font-size: 0.85rem; font-weight: 600; color: var(--brand-text); margin-bottom: 8px; }
.col-more > summary::-webkit-details-marker { display: none; }
.col-more > summary:hover { background: var(--brand-050); }
.col-more__close, .col-more[open] .col-more__open { display: none; }
.col-more[open] .col-more__close { display: inline; }
/* หมวดสินค้า: the owner ticks are colour chips like every other person picker; each chip hugs its name */
.td-owners .owner-checks label.who { justify-self: start; }
/* รอมอบหมาย: the number + details block at the left, ✋ รับงานนี้ at the right centred across it (triage.html) */
.q-top { display: flex; align-items: center; gap: 8px 16px; }
.q-top__text { flex: 1 1 auto; min-width: 0; }
.q-top__text > .case-meta { margin-bottom: 0; }
.q-top > .q-claim { flex: none; margin: 0; }
@media (max-width: 640px) { .q-top { flex-wrap: wrap; } .q-top > .q-claim { flex-basis: 100%; } }
/* รอมอบหมาย: มอบหมายทั้ง PR and แบ่งงานตามรายการ in two columns while closed (one alone fills the row; a phone
   stacks them); an opened fold takes the whole row, so its line list and name chips keep the card's width */
.q-blocks { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 10px; margin-top: 10px; }
.q-blocks > .q-block { margin-top: 0; min-width: 0; }
/* They act as two buttons (the user, 2026-10-08): closed, an outline button each; pressing one hides the
   other and opens its form across the card under a header; pressing the header closes it and both come back. */
.q-blocks > .q-block:not([open]) { background: var(--surface); border: 1.5px solid var(--border-strong); border-radius: var(--radius-xl); }
.q-blocks > .q-block:not([open]):hover { background: var(--brand-050); }
.q-blocks > .q-block:not([open]) > summary { display: flex; align-items: center; justify-content: center; gap: 6px;
  min-height: var(--size-tap); list-style: none; color: var(--brand-text); }
.q-blocks > .q-block > summary::-webkit-details-marker { display: none; }
.q-blocks > .q-block[open] > summary { display: flex; align-items: center; gap: 6px; list-style: none; }
.q-blocks > .q-block[open] > summary::after { content: "✕"; margin-left: auto; font-size: 0.85rem; color: var(--ink-muted); }
.q-blocks:has(> .q-block[open]) > .q-block { grid-column: 1 / -1; }
.q-blocks:has(> .q-block[open]) > .q-block:not([open]) { display: none; }

/* ── Approval detail (templates/approval_detail.html, 2026-10-08, Praew: "too many buttons and links") ──
   One "เปิดใน Lark ↗" link in the header; under ข้อมูลในแบบฟอร์ม one actions card: the head's flow on one
   line — วันกำหนดส่ง, วันส่งมอบงาน, เลือกผู้ดูแลงาน, มอบหมาย + ยืนยัน, ยกเลิกงานนี้ — every control one height
   (--size-tap), then the caretakers' status row. A phone stacks the controls, full width, in the same order. */
.apr-head-links { display: inline-flex; align-items: center; gap: 14px; }
.apr-lark-link { font-size: 0.85rem; color: var(--brand-text); white-space: nowrap; }
.apr-actions:not(:has(form, details, .action-hint, .appr-cancelled, .footnote)) { display: none; }
.apr-actions > .action-bar:not(:has(form, .action-hint, .appr-cancelled)) { display: none; }
.apr-actions > .action-bar:first-child { border-top: 0; padding-top: 0; margin-top: 0; }
.apr-panel { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 22px 12px; }
.apr-date { position: relative; display: flex; flex-direction: column; gap: 4px; flex: 0 1 190px; min-width: 165px; margin: 0; }
.apr-date__label { font-size: 0.78rem; font-weight: 600; color: var(--ink-muted); }
.apr-panel .date-display { min-height: var(--size-tap); padding: 0 0.8rem; font-size: 0.95rem; }
.apr-saved { position: absolute; top: 100%; left: 2px; margin-top: 2px; font-size: 0.74rem; color: var(--ink-muted); white-space: nowrap; }
.apr-saved.is-ok { color: var(--pill-success); }
.apr-saved.is-err { color: var(--danger); }
/* the picker and its button never part: the whole form wraps to the next line instead */
.apr-panel .apr-act { flex: 0 0 auto; flex-wrap: nowrap; align-items: flex-end; }
.apr-panel .owner-picker { flex: 0 0 240px; }
.apr-panel .owner-picker > summary { box-sizing: border-box; min-height: var(--size-tap); display: flex; align-items: center; border-color: var(--border-strong);
  justify-content: space-between; }
.page-content .apr-panel .apr-act__btn { min-height: var(--size-tap); padding: 0 18px; font-size: 0.95rem; border-radius: var(--radius-xl); }
.apr-panel .appr-cancel { width: auto; }
.apr-panel .appr-cancel > summary { box-sizing: border-box; min-height: var(--size-tap); padding: 0 16px; border-style: solid;
  border-radius: var(--radius-xl); background: var(--surface); font-weight: 600; }
.apr-panel .appr-cancel[open] { flex-basis: 100%; }
.apr-panel__note { margin: 10px 0 0; }
.apr-record-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.apr-record-title .apr-sync { margin: 0 0 0 auto; }
.apr-history > summary { display: flex; align-items: center; gap: 8px; list-style: none; cursor: pointer; }
.apr-history > summary::-webkit-details-marker { display: none; }
.apr-history > summary::before { content: "›"; display: inline-block; color: var(--ink-muted); transition: transform 120ms ease; }
.apr-history[open] > summary::before { transform: rotate(90deg); }
@media (max-width: 640px) {
  .apr-date, .apr-panel .apr-act, .apr-panel .owner-picker, .apr-panel .appr-cancel { flex: 1 1 100%; }
  .apr-panel .apr-act { flex-wrap: wrap; }
  .apr-panel .apr-act__btns, .page-content .apr-panel .apr-act__btn, .apr-panel .appr-cancel > summary { width: 100%; justify-content: center; }
  .apr-head-links { width: 100%; justify-content: space-between; }
}
/* two columns like the PR case page (2026-10-08): ข้อมูลในแบบฟอร์ม + the record on the left, the actions in a
   sticky right column; a phone stacks form data → actions → the rest */
.apr-cols { display: flex; flex-direction: column; gap: var(--space-4); margin-top: var(--space-4); }
.apr-form { order: 1; min-width: 0; }
.apr-side { order: 2; display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }
.apr-rest { order: 3; min-width: 0; }
.apr-form > .section-title:first-child { margin-top: 0; }
.apr-side .card { margin: 0; }
@media (min-width: 1024px) {
  .apr-cols { display: grid; grid-template-columns: minmax(0, 1fr) 360px; grid-template-areas: "form side" "rest side";
    align-items: start; column-gap: var(--space-4); row-gap: 0; }
  .apr-form { grid-area: form; } .apr-rest { grid-area: rest; }
  /* sticks below the top bar like the PR case page's side column, and scrolls within itself when taller */
  .apr-side { grid-area: side; position: sticky; top: calc(var(--hdr-h) + var(--space-4));
    max-height: calc(100vh - var(--hdr-h) - var(--space-8)); overflow-y: auto; overscroll-behavior: contain; }
  /* the side column is narrow: every action takes the full width, in Praew's order */
  .apr-side .apr-date, .apr-side .apr-panel .apr-act, .apr-side .apr-panel .owner-picker, .apr-side .apr-panel .appr-cancel { flex: 1 1 100%; }
  .apr-side .apr-panel .apr-act { flex-wrap: wrap; }
  .apr-side .apr-panel .apr-act__btns, .page-content .apr-side .apr-panel .apr-act__btn, .apr-side .apr-panel .appr-cancel > summary { width: 100%; justify-content: center; }
  .apr-side .action-bar > form, .apr-side .action-bar .action-solo .btn { width: 100%; }
}
/* the columns wrap the section titles, so they take the page's own title spacing here; the right column has a
   title too ("การดำเนินการ"), so both columns' cards start on the same line (2026-10-09) */
.apr-cols :is(.apr-form, .apr-rest, .apr-side) > .section-title,
.apr-cols :is(.apr-form, .apr-rest, .apr-side) > [data-apr-live] > .section-title { margin: 1.5rem 0 0.7rem; font-size: 1.05rem; }
.apr-cols :is(.apr-form, .apr-side) > .section-title:first-child { margin-top: 0; }
.apr-side { gap: 0; }
.apr-side > [data-apr-live] + [data-apr-live] > .card { margin-top: var(--space-4); }
.apr-side:not(:has(.lark-open, .apr-actions :is(form, details, .action-hint, .appr-cancelled, .footnote))) > .apr-side__title { display: none; }
/* ประวัติ's title is the summary of its fold, one level deeper: the same title spacing */
.apr-cols .apr-history { margin-top: 1.5rem; }
.apr-cols .apr-history > summary.section-title { margin: 0 0 0.7rem; font-size: 1.05rem; }
/* คำขอ PR: the work map's steps share the band's width like the PR case page's stepper (2026-10-09); a phone
   keeps the sideways-scrolling row of fixed steps */
.cd-wmap .wmap__step { flex: 1 1 0; max-width: none; }
@media (max-width: 640px) { .cd-wmap .wmap__step { flex: 0 0 auto; max-width: 168px; } }
/* A table cell's second line (the PO's age "4 วัน", จ่ายบางส่วน, รับแล้ว 1/2 รอบ, who/when) is small and muted
   (2026-10-09). Only the <div> lines — an a.item-sub is a link (TRCloud ↗) and keeps its link colour. */
.wl-table td > div.item-sub { margin-top: 2px; font-size: 0.74rem; color: var(--ink-muted); }
/* "0 / 22 กก.": units already opened as PO, of the line's quantity (2026-10-09) — the "of" part is lighter */
.tb-l-of { color: var(--ink-muted); white-space: nowrap; }
/* แผนสั่งซื้อ: how the page reads its sources — two small groups, one point per line (templates/plans.html) */
.plan-notes { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 12px 28px; margin-top: 16px;
  font-size: 0.82rem; color: var(--ink-muted); }
.plan-notes__title { margin: 0 0 4px; font-weight: 600; color: var(--ink); }
.plan-notes ul { margin: 0; padding-left: 1.1rem; display: grid; gap: 3px; }

/* ── แผนสั่งซื้อ: the sources as boxes grouped by where they live (templates/plans.html, 2026-10-09) ── */
/* the two groups share one line when they fit (the user, 2026-10-09), and wrap to two when not */
.plan-src { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 28px; margin: 0 0 14px; }
.plan-src__label { display: block; margin-bottom: 4px; font-size: 0.76rem; font-weight: 600; color: var(--ink-muted); }
.plan-src__row { display: flex; flex-wrap: wrap; gap: 8px; }
.plan-src__box { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "name count" "sub sub";
  align-items: baseline; column-gap: 10px; row-gap: 2px; min-width: 118px; padding: 8px 11px;
  border: 1.5px solid var(--border); border-radius: var(--radius-md); background: var(--surface); color: var(--ink);
  text-decoration: none; }
.plan-src__box:hover { border-color: var(--border-strong); }
.plan-src__box.is-active { border-color: var(--brand-600); background: var(--brand-050); }
.plan-src__box:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.plan-src__name { grid-area: name; font-size: 0.9rem; font-weight: 600; white-space: nowrap; }
.plan-src__count { grid-area: count; font-size: 0.85rem; font-weight: 600; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.plan-src__sub { grid-area: sub; font-size: 0.74rem; color: var(--ink-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.plan-src__brand { display: inline-block; padding: 0 8px; border-radius: 999px; background: var(--track); color: var(--ink);
  font-weight: 600; line-height: 1.6; }
/* a brand's name chip in its own logo colour (One Platform "Brand colours", fixed in both themes) */
.plan-src__brand--yoguruto { background: var(--brand-yoguruto); color: var(--on-brand-yoguruto); }
.plan-src__brand--beluga { background: var(--brand-beluga); color: var(--on-brand-beluga); }
.plan-src__brand--nuts-yes, .plan-src__brand--nuts { background: var(--brand-nuts); color: var(--on-brand-nuts); }
@media (max-width: 640px) { .plan-src__box { flex: 1 1 calc(50% - 4px); min-width: 0; } .plan-src__name, .plan-src__sub { white-space: normal; } }
/* แผนสั่งซื้อ: the source line — text, then two small outline buttons on the same line (templates/plans.html) */
.plan-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 0 0 10px; font-size: 0.82rem; color: var(--ink-muted); }
.plan-meta__form { display: contents; }
.page-content .plan-meta__btn { display: inline-flex; align-items: center; gap: 4px; min-height: 30px; padding: 2px 12px;
  border: 1.5px solid var(--border-strong); border-radius: var(--radius-xl); background: var(--surface); color: var(--brand-text);
  font: inherit; font-size: 0.8rem; font-weight: 600; text-decoration: none; cursor: pointer; white-space: nowrap; }
.page-content .plan-meta__btn:hover { background: var(--brand-050); }
.page-content .plan-meta__btn.is-zero { color: var(--ink-muted); font-weight: 500; }
.plan-meta__by { font-weight: 400; color: var(--ink-muted); }
/* Two cards one after the other never touch (2026-10-09: ช่องทางซัพพลายเออร์, รายงาน had 0px); where a card
   already brings a bottom margin the two collapse to the larger, so other pages keep their spacing */
.page-content > .card + .card { margin-top: 14px; }
/* บัญชี Supplier: the search row is the app's filter row; the search box takes the free width */
.sup-filter input[type="search"] { flex: 1 1 260px; max-width: 420px; }

/* ── ทีม & ตั้งค่า: folding sections + a jump bar (templates/admin_members.html, 2026-10-09) ── */
.set-jump { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0 0 6px; }
.set-jump a, .set-jump__all { display: inline-flex; align-items: center; min-height: 32px; padding: 2px 12px;
  border: 1.5px solid var(--border); border-radius: var(--radius-xl); background: var(--surface);
  color: var(--ink); font: inherit; font-size: 0.82rem; font-weight: 600; text-decoration: none; cursor: pointer; }
.set-jump a:hover { border-color: var(--border-strong); background: var(--surface-hover); }
.set-jump__all { margin-left: auto; color: var(--brand-text); border-color: var(--border-strong); }
.set-fold { scroll-margin-top: calc(var(--hdr-h) + var(--space-4)); }
.set-fold > summary.section-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 1.5rem 0 0.7rem;
  font-size: 1.05rem; list-style: none; cursor: pointer; }
.set-fold > summary.section-title::-webkit-details-marker { display: none; }
.set-fold > summary.section-title::before { content: "›"; display: inline-block; width: 0.8em; color: var(--ink-muted);
  transition: transform 120ms ease; }
.set-fold[open] > summary.section-title::before { transform: rotate(90deg); }
.set-fold:not([open]) > summary.section-title { margin-bottom: 0; }
/* A note of several points, one per line (ทีม & ตั้งค่า, 2026-10-09) — the footnote's size and colour */
.note-list { display: grid; gap: 3px; margin: 0 0 12px; padding-left: 1.1rem; font-size: 0.82rem; color: var(--ink-muted); }
.note-list b { color: var(--ink); }
.card + .note-list, .wl-table-wrap + .note-list { margin-top: 10px; }   /* a footnote list under a table card keeps a gap */
.card > .note-list:last-child { margin: 10px 0 0; }   /* …and one closing a card adds no bottom margin */

/* ── กฎการทำงาน: one setting per row (templates/admin_rules.html #assign-rules, 2026-10-09) ── */
.rule-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 8px 32px;
  padding: 14px 0; border-top: 1px solid var(--border); }
.rule-row:first-child { padding-top: 0; border-top: 0; }
.rule-row__title { display: block; margin: 0; font-weight: 600; color: var(--ink); }
.rule-row__hint { margin: 2px 0 0; font-size: 0.85rem; color: var(--ink-muted); }
.rule-row__meta { margin: 6px 0 0; font-size: 0.78rem; color: var(--ink-muted); }
.rule-row__ctl { display: flex; align-items: center; gap: 8px; justify-self: end; font-size: 0.9rem; }
.rule-row__ctl .checkbox-inline { font-size: 0.9rem; font-weight: 600; }
.rule-rows__foot { display: flex; justify-content: flex-end; padding-top: 12px; border-top: 1px solid var(--border); }
@media (max-width: 640px) { .rule-row { grid-template-columns: minmax(0, 1fr); } .rule-row__ctl { justify-self: start; }
  .rule-rows__foot { justify-content: flex-start; } }   /* clear of the ถามบอท button at the bottom right */

/* owner_pick_one — one person in a form field (คำขอ PR ผู้ดูแลงาน / ผู้ช่วยดูแลงาน, 2026-10-09): the summary
   takes the field's full width and height, like the <select> beside it */
.field .owner-picker--one > summary { box-sizing: border-box; width: 100%; max-width: none; min-height: var(--size-tap);
  display: flex; justify-content: space-between; padding: 0 0.8rem; border: 1px solid var(--border-strong);
  border-radius: var(--radius-md); font-size: 0.95rem; line-height: normal; }
.field .owner-picker--one > summary > span:first-child { overflow: hidden; text-overflow: ellipsis; }
.owner-picker--one .owner-picker-none { color: var(--ink-muted); padding: 4px 9px; }
.owner-picker--one .owner-picker-menu.is-floating { padding-bottom: 10px; }   /* no sticky foot to give the last name its space */
/* inside a form field, `.field label` (block, bold, a bottom margin) must not reach the picker's rows —
   it doubled the gap between names (the user, 2026-10-09: "should have the same spacing as approval") */
.field .owner-picker label.owner-picker-opt { display: flex; margin: 0; font-weight: 400; line-height: 1.45; }

/* a rule-row whose control needs the width (a long select + its button): text above, control below */
.rule-row--stack { grid-template-columns: minmax(0, 1fr); }
.rule-row--stack .rule-row__ctl { justify-self: stretch; }
.sup-invite { flex-wrap: wrap; gap: 10px; }
.sup-invite select { flex: 1 1 260px; min-width: 0; min-height: var(--size-tap); padding: 0 12px; border: 1px solid var(--border-strong);
  border-radius: var(--radius-md); background: var(--surface); color: var(--ink); font: inherit; font-size: 0.95rem; }
@media (max-width: 640px) { .sup-invite select { flex-basis: 100%; } }   /* the button goes under the select on a phone */
.card > h3 + .rule-rows { margin-top: 14px; }

/* คำขอ PR: "มอบหมาย / เลือกผู้ดูแลงาน" rings the ผู้ดูแลงาน box it jumped to (static/prq.js, 2026-10-09) */
@keyframes prq-call { 0%, 30% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--brand-600) 35%, transparent); }
  100% { box-shadow: 0 0 0 4px transparent; } }
.owner-picker.is-called > summary { border-color: var(--brand-600); animation: prq-call 1.2s ease-out 2; }
@media (prefers-reduced-motion: reduce) {
  .owner-picker.is-called > summary { animation: none; box-shadow: 0 0 0 4px color-mix(in srgb, var(--brand-600) 35%, transparent); }
}

/* the bulk bar's person picker (templates/_list_tools.html member_select, 2026-10-09): one height with the bar */
.tb-bulk .owner-picker > summary { display: flex; justify-content: space-between; box-sizing: border-box; width: 190px; max-width: 100%;
  height: var(--size-control-sm); font-size: 0.9rem; border-color: var(--border-strong); }
.tb-bulk .owner-picker > summary > span:first-child { overflow: hidden; text-overflow: ellipsis; }

/* a person filter in a filter row (_list_tools.html person_field, 2026-10-09): the row's 40px, like its selects */
.tb-prf .field .owner-picker--one > summary { height: var(--size-control-sm); min-height: 0; padding: 6px 8px; font-size: 0.85rem;
  border: 1.5px solid var(--border); border-radius: 8px; background: var(--surface); }

/* UAT only (uat_app.py sets `uat`): one strip above everything, so a copy of live data is never taken for live */
.uat-strip { position: sticky; top: 0; z-index: 100; padding: 4px 12px; text-align: center; font-size: 0.8rem; font-weight: 600;
  background: var(--warning-surface); color: var(--warning); border-bottom: 1px solid var(--border); }   /* --warning: 4.6:1 light, 8.7:1 dark; --pill-warning was 2.6:1 */

/* -- /admin/members#prq-cancel-groups: who may cancel a คำขอ PR by category (2026-10-12) --
   One block per group inside the section's card; a switched-off group is drawn muted. */
.prq-cg { padding: 12px 0 14px; border-top: 1px solid var(--border); }
.prq-cg:first-of-type { border-top: 0; padding-top: 4px; }
.prq-cg--off > .prq-cg__form, .prq-cg--off > .wl-table-wrap { opacity: 0.6; }
.prq-cg__form textarea { min-width: 240px; font-size: 0.92rem; }
.prq-cg__covered { margin: 8px 0; }
.prq-cg__people { margin: 0; }
.prq-cg__add { margin-top: 10px; }
.prq-cg__add > label { display: block; font-size: 0.85rem; font-weight: 600; margin-bottom: 4px; }
.prq-cg__add textarea { margin-bottom: 0.3rem; }
.prq-cg__log { margin-top: 12px; }
.prq-cg__log > summary { cursor: pointer; }

/* ===== ติดตามงานจ้าง (/hire, 2026-10-13 — lark_hire.py, templates/hire.html) =====
   The mirrored contractor jobs: eight columns on a desktop — they fit 1366px with the sidebar open, so
   "เปิดใน Base" is never off to the right; at phone width a job is a card on the SAME <tr>/<td> (labels
   from data-label), like the claims list. Words break only where they must (break-word, not anywhere:
   `anywhere` lets a column shrink until a Thai name is cut mid-word). */
.hire-tables { margin-bottom: 12px; }
/* What needs updating, first on the page: up to four boxes, each a link to the rows it counts. */
.hire-todo { margin-bottom: 12px; }
.hire-todo__title { font-weight: 700; margin-bottom: 8px; }
.hire-todo__boxes { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 10px; }
.hire-todo__box { display: block; text-decoration: none; min-height: 44px; }
.hire-todo__box:hover, .hire-todo__box:focus-visible { border-color: var(--primary); }
.hire-todo__box .v { display: block; }
.hire-todo__box .k { display: block; font-size: 0.8rem; line-height: 1.45; }
.hire-todo .footnote { margin: 8px 0 0; }
.hire-tables__list td { white-space: normal; overflow-wrap: break-word; }
.hire-lacks { color: var(--warning); margin-top: 3px; }
.hire-why { font-size: 0.8rem; overflow-wrap: anywhere; }
.hire-table { min-width: 760px; }
.hire-table th, .hire-table td { padding-left: 8px; padding-right: 8px; }
.hire-table td { white-space: normal; }
.hire-table .td-job { min-width: 150px; max-width: 280px; overflow-wrap: break-word; }
.hire-table td:nth-child(2) { min-width: 110px; max-width: 190px; overflow-wrap: break-word; }
.hire-table td:nth-child(3) { min-width: 124px; max-width: 220px; overflow-wrap: anywhere; }   /* one PO number on one line; free text wraps */
.hire-table td:nth-child(4) { max-width: 150px; }
.hire-table td:nth-child(4) .chip { white-space: normal; border-radius: 11px; }
.hire-table .hire-status { white-space: normal; border-radius: 11px; }
/* A label and its value stay on one line (กำหนดส่ง 30/06/2026); the chip goes under it when there is no room. */
.hire-table .hire-line { line-height: 1.7; }
.hire-table .hire-kv { white-space: nowrap; }
.hire-table .hire-kv > .small:first-child { display: inline-block; min-width: 4.3em; }
.hire-table .hire-kv [data-date-raw] { white-space: normal; }
.hire-table .hire-line .badge { font-size: 0.72rem; padding: 1px 8px; }
.hire-table .nowrap { white-space: nowrap; }
@media (max-width: 640px) {
  .hire-table { min-width: 0; display: block; }
  .hire-table tbody { display: block; }
  .hire-table tr { display: block; padding: 10px 2px; border-bottom: 1px solid var(--border); }
  .hire-table tr:first-child { display: none; }
  .hire-table td { display: block; border: 0; padding: 2px 0; min-width: 0 !important; max-width: none !important; }
  .hire-table td[data-label]::before { content: attr(data-label); display: block; font-size: 0.7rem;
    color: var(--ink-muted); margin-top: 4px; }
  .hire-table td.td-job { font-size: 1rem; }
  .hire-table td.td-job::before { display: none; }
  .hire-table td.nowrap { white-space: normal; }
  .hire-table td.empty-cell { text-align: center; }
  .hire-tables__list th, .hire-tables__list td { padding: 7px 6px; font-size: 0.82rem; }
}
/* ใบส่งมอบในโฟลเดอร์ (/hire?tab=inbox, 2026-10-14 — hire_inbox.py, templates/_hire_inbox.html): one card per
   proposal, the same markup at every width; the two dates are a small table that stacks on a phone. */
.inbox-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
.inbox-notwritten, .inbox-writing { margin: 8px 0 12px; }
/* What hire_write.py wrote for a proposal, or why not (2026-10-15). */
.inbox-write { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; overflow-wrap: anywhere; }
.inbox-p { margin-bottom: 12px; display: flex; flex-direction: column; gap: 8px; overflow-wrap: break-word; }
.inbox-p__file a, .inbox-p__file [data-file-name] { font-weight: 600; overflow-wrap: anywhere; }
.inbox-pick { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.inbox-pick select { max-width: 100%; min-height: 36px; background: var(--surface); }
.inbox-dates { width: 100%; }
.inbox-dates td, .inbox-dates th { white-space: normal; vertical-align: top; }
.inbox-dates td:first-child { font-weight: 600; width: 9em; }
.inbox-p__acts { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start; }
.inbox-edit > summary { list-style: none; cursor: pointer; }
.inbox-edit > summary::-webkit-details-marker { display: none; }
.inbox-edit__form { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end; margin-top: 8px; }
.inbox-edit__form label { display: flex; flex-direction: column; font-size: 0.82rem; gap: 2px; }
.inbox-edit__form input[type=date] { min-height: 36px; }
.inbox-done, .inbox-problems { margin-bottom: 12px; }
.inbox-problems ul { margin: 0; padding-left: 18px; }
.inbox-problems li { margin: 4px 0; overflow-wrap: anywhere; }
@media (max-width: 640px) {
  .inbox-dates tr:first-child { display: none; }
  .inbox-dates tr, .inbox-dates td { display: block; border: 0; padding: 2px 0; width: auto !important; }
  .inbox-dates tr { padding: 6px 0; border-bottom: 1px solid var(--border); }
  .inbox-dates td[data-label]:not(:first-child)::before { content: attr(data-label); display: block; font-size: 0.7rem; color: var(--ink-muted); }
  .inbox-p__acts .btn, .inbox-pick .btn, .inbox-pick select { min-height: 40px; }
}

/* ขอเปลี่ยนสถานะ PR (2026-10-14, status_requests.py): one card per request — the case page and /status-requests. */
.sr-card { border: 1px solid #e3e8e4; border-left: 4px solid var(--primary); border-radius: 8px; padding: 10px 12px; margin: 8px 0; }
.sr-card--pending { border-left-color: #d97706; background: #fffbeb; }
.sr-card--rejected, .sr-card--void { border-left-color: var(--danger); }
.sr-card--withdrawn { border-left-color: #9ca3af; }
.sr-card__meta, .sr-card__decision { font-size: 0.85rem; color: #4b5563; margin-top: 4px; }
.sr-card__reason { margin-top: 6px; white-space: pre-wrap; }
.sr-card__blocked { margin-top: 6px; color: var(--warning); background: var(--warning-bg); padding: 4px 8px; border-radius: 6px; }
.sr-card__act { margin-top: 8px; }
.sr-pos { margin: 6px 0 0; padding-left: 18px; font-size: 0.9rem; overflow-wrap: anywhere; }
.sr-pos li { margin: 2px 0; }
.sr-pos--other { background: #fef3c7; border-radius: 4px; }
.sr-warn { color: var(--warning); font-weight: 600; }
.sr-state--pending { background: #fef3c7; color: #92400e; }
.sr-state--approved { background: #d1fae5; color: #065f46; }
.sr-state--rejected, .sr-state--void { background: #fee2e2; color: #991b1b; }
.sr-state--withdrawn { background: #f3f4f6; color: #4b5563; }
.my-sr-link { display: inline-block; margin-top: 4px; }
/* ถามบอท's ขอเปลี่ยนสถานะ card (2026-10-14, static/prq-bot.js renderStatusCard) */
.prqbot__card { align-self: stretch; border: 1px solid #e3e8e4; border-radius: 10px; padding: 8px 10px; background: #fff; font-size: 0.85rem; display: flex; flex-direction: column; gap: 4px; }
.prqbot__warn { color: var(--warning); }
.prqbot__reason { width: 100%; min-height: 56px; font: inherit; }

/* วิธีใช้หน้านี้ (critique 2026-10-16): a page's rules folded into one quiet line — read once, then out of the
   way of the work. The list / legend inside keeps its own styles. */
.page-help { margin: 0 0 12px; font-size: 0.84rem; }
.card + .page-help, .wl-table-wrap + .page-help { margin-top: 10px; }
.page-help > summary {
  display: inline-flex; align-items: center; gap: 6px; min-height: 32px; cursor: pointer; list-style: none;
  color: var(--brand-text); font-weight: 600;
}
.page-help > summary::-webkit-details-marker { display: none; }
.page-help > summary::before {
  content: ""; width: 7px; height: 7px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-45deg); transition: transform 150ms ease-out;
}
.page-help[open] > summary::before { transform: rotate(45deg); }
.page-help > summary:hover { text-decoration: underline; text-underline-offset: 3px; }
.page-help[open] > :not(summary) { margin-top: 6px; }
.page-help > .note-list { margin-bottom: 0; }
.page-help--apr > .apr-help { margin-top: 6px; }

/* ===== Approval lists + บอร์ดทีม's PR list as one card per row on a phone (critique 2026-10-16) =====
   The same <tr>/<td>, captions from data-label (the คำขอ PR pattern, prq-phone.css): nothing scrolls
   sideways, so the ผู้ดูแล picker and the row's buttons are always on screen. The header row keeps
   only its select-all box. */
@media (max-width: 640px) {
  .card.wl-table-wrap:has(> .appr-table), .card.wl-table-wrap:has(> .tb-table) {
    background: none; box-shadow: none; border: 0; padding: 0; overflow: visible; }
  .appr-table, .appr-table > tbody, .tb-table, .tb-table > tbody { display: block; width: 100%; min-width: 0; }
  .appr-table tr:has(> th), .tb-table tr:has(> th) { display: flex; align-items: center; padding: 0 2px 8px; }
  .appr-table tr:has(> th):not(:has(> th.tb-pick)), .tb-table tr:has(> th):not(:has(> th.tb-pick)) { display: none; }
  .appr-table tr:has(> th) > th:not(.tb-pick), .tb-table tr:has(> th) > th:not(.tb-pick) { display: none; }
  .appr-table th.tb-pick, .tb-table th.tb-pick { display: flex; align-items: center; gap: 8px; padding: 0 0 0 14px;
    border: 0; background: none; font-weight: 600; color: var(--ink-muted); }
  .appr-table th.tb-pick::after, .tb-table th.tb-pick::after { content: "เลือกทั้งหมด"; font-size: 0.82rem; }
  .appr-table tr[id], .tb-table tr[id^="c"] {
    display: flex; flex-wrap: wrap; align-items: flex-start; gap: 6px 10px; position: relative;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md);
    box-shadow: var(--shadow-card); padding: 12px 14px; margin-bottom: 10px; }
  .appr-table tr.wl-row-overdue, .tb-table tr.wl-row-overdue { background: var(--danger-surface); border-color: var(--danger-dot); }
  .appr-table tr.wl-row-due { background: var(--warning-surface); border-color: var(--warning-dot); }
  .appr-table tr[id] > td, .tb-table tr[id^="c"] > td {
    display: block; flex: 1 1 100%; min-width: 0; max-width: none; width: auto; padding: 0; border: 0;
    white-space: normal; overflow-wrap: anywhere; background: none; position: static; line-height: 1.55; }
  .appr-table tr[id] > td.tb-pick, .tb-table tr[id^="c"] > td.tb-pick { flex: none; order: 0; padding-top: 2px; }
  .appr-table tr[id] > td.td-doc, .tb-table tr[id^="c"] > td.td-doc { order: 1; flex: 1 1 0; font-size: 0.95rem; }
  .appr-table tr[id] > td[data-label], .tb-table tr[id^="c"] > td[data-label] {
    order: 5; position: relative; padding-left: 5.8rem; min-height: 1.55em; }
  .appr-table tr[id] > td[data-label]::before, .tb-table tr[id^="c"] > td[data-label]::before {
    content: attr(data-label); position: absolute; left: 0; top: 2px; width: 5.4rem;
    color: var(--ink-muted); font-size: 0.78rem; line-height: 1.6; }
  .appr-table tr[id] > td.td-act { order: 9; margin-top: 4px; padding-top: 10px; border-top: 1px solid var(--border); }
  .appr-table td.td-act .apr-act__ask { margin-left: 0; }
  .appr-table td:not(.td-act) > .apr-turn { min-width: 0; max-width: none; }
  .tb-table tr.tb-detail { display: block; }
  .tb-table tr.tb-detail > td { display: block; padding: 0 0 10px; border: 0; }
  .tb-detail__box { position: static; width: auto; }
  .appr-table tr:not([id]):not(:has(> th)), .tb-table tr:not([id]):not(:has(> th)) { display: block; }
}

/* Approval page on a phone (critique 2026-10-16): the summary's nine facts in two columns, and a jump to
   การดำเนินการ beside ← กลับ — the actions stay after ข้อมูลในแบบฟอร์ม (the head's order of 2026-10-08). */
.apr-jump { display: none; }
@media (max-width: 1023px) { .apr-jump { display: inline-flex; } }
@media (max-width: 640px) {
  [data-apr-live="head"] .detail-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 12px; }
  [data-apr-live="head"] .detail-grid > .item--owners { grid-column: span 2; }
  #apr-actions { scroll-margin-top: 12px; }
}

/* ปิดใช้งาน on ทีม (critique 2026-10-16): switching a person off is not a routine button beside โอนงาน —
   set apart, in the quiet danger look, and confirmed. */
.member-actions .member-off { margin-left: 10px; }
.btn-outline.btn-quiet-danger { color: var(--danger); border-color: var(--danger-dot); }
.btn-outline.btn-quiet-danger:hover { background: var(--danger-surface); color: var(--danger); border-color: var(--danger); }

/* A closed picker's menu takes no room (critique 2026-10-16): Chromium still laid out the bulk bar's
   closed menu, which ran 25px past a 390px phone and gave the page a sideways scroll. */
details.owner-picker:not([open]) > .owner-picker-menu { display: none; }
.appr-table th.tb-pick, .tb-table th.tb-pick { white-space: nowrap; }
/* …and a closed fold inside a list (ดูรายการ, รายการสินค้า) takes none either: its item table was laid out
   at full width while hidden and widened the phone cards. */
.wl-table details:not([open]) > :not(summary) { display: none; }
@media (max-width: 640px) {
  .appr-table tr[id] > td.td-act::after { content: none; }   /* the sticky column's edge shade has no column to edge here */
}
