/* Shared styling for the shop and the order desk.
   ==========================================================================
   One stylesheet, tokens only, no framework and no webfont. A customer
   reaching this page is deciding whether to trust it with money on a phone
   connection at a market; every kilobyte and every round trip is spent
   against that.

   Dark mode follows the device. Without `color-scheme`, Chrome on Android
   applies its own automatic inversion, and the one thing on this page that
   must never be inverted is the QR code — an inverted QR does not scan on
   many readers, so it is painted on its own explicit white and stays there.
   ========================================================================== */

:root {
  color-scheme: light dark;

  --bg: #F4F6FA;
  --surface: #FFFFFF;
  --surface-alt: #F8F9FC;
  --border: #E2E7EF;
  --border-strong: #C8D1E0;
  --text: #16202E;
  --muted: #5C6B7F;
  /* วัดแล้วว่าค่าเดิม #6B7687 ได้ contrast 4.37 บน --surface-alt และ 4.25
     บน --bg ซึ่งต่ำกว่าเกณฑ์ WCAG AA ที่ 4.5 ทั้งคู่ ค่านี้เข้มขึ้นเล็กน้อย
     จนตาแทบไม่เห็นความต่าง แต่ผ่านทุกพื้นหลัง — 4.91 · 5.17 · 4.78
     (ค่าของโหมดมืดวัดแล้วผ่านอยู่แล้ว จึงไม่แตะ) */
  --faint: #646E7C;

  --brand: #14532D;
  --brand-text: #0F4024;
  --on-brand: #FFFFFF;
  --accent: #1D4FD8;

  --ok: #0A7A67;
  --ok-bg: #E3F6F1;
  --warn-text: #8A5A00;
  --warn-bg: #FDF3DC;
  --danger: #B42318;
  --danger-bg: #FCE9E7;

  --radius: 12px;
  --shadow: 0 1px 2px rgba(16, 32, 46, .06), 0 8px 24px rgba(16, 32, 46, .06);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0E131B;
    --surface: #171E29;
    --surface-alt: #1C2431;
    --border: #2A3442;
    --border-strong: #3C4859;
    --text: #E6EBF2;
    --muted: #9FADBF;
    --faint: #8090A6;

    --brand: #2F7D4F;
    --brand-text: #7FD6A2;
    --on-brand: #F2FBF5;
    --accent: #8FB4FF;

    --ok: #5FE3C0;
    --ok-bg: #10312B;
    --warn-text: #F0C36A;
    --warn-bg: #33280C;
    --danger: #FFA39E;
    --danger-bg: #3A1D1B;

    --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px rgba(0, 0, 0, .45);
  }
}

* { box-sizing: border-box; }

html, body { margin: 0; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, 'Segoe UI', 'Noto Sans Thai', sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: 720px; margin: 0 auto; padding: 20px 16px 60px; }
.wide { max-width: 1100px; }

h1 { font-size: 1.5rem; margin: 0 0 4px; line-height: 1.3; }
h2 { font-size: 1.1rem; margin: 28px 0 12px; }
p { margin: 0 0 12px; }
.sub { color: var(--muted); font-size: .92rem; margin-bottom: 20px; }

/* Read aloud but never painted. */
.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;
}

/* An unmistakable focus ring. Someone filling in an address by keyboard
   has to be able to see where they are without hunting for a hairline. */
:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 14px;
  box-shadow: var(--shadow);
}

/* -------------------------------------------------------------- products */

/*
 * การ์ดสินค้าเป็นสามแถวซ้อนกัน ไม่ใช่กริดสองคอลัมน์
 *
 * เดิมเป็น `grid-template-columns: 1fr auto` แล้วจัดที่ลูกแต่ละตัวด้วย
 * grid-column ซึ่งทำให้ **ปุ่ม − 0 + เป็นคนกำหนดความกว้างของทุกแถว** เพราะ
 * คอลัมน์ที่สองเป็น auto จึงกว้างตามของที่กว้างที่สุดในคอลัมน์นั้น คือปุ่ม
 * จำนวน (~140px)
 *
 * วัดจากของจริงบนจอ 390px: เนื้อที่ในการ์ด 332px แต่คำอธิบายได้แค่ 175px
 * คือ 53% ทั้งที่แถวของคำอธิบายไม่มีอะไรอยู่ในคอลัมน์สองเลย — ที่ว่างครึ่งขวา
 * ถูกจองไว้ให้ปุ่มที่อยู่คนละแถว และชื่อสินค้าก็เสียที่ไปด้วยแบบเดียวกัน
 * ทั้งที่ราคาต้องการแค่ ~70px
 *
 * แยกเป็นแถวด้วยตัวครอบ (.p-head .p-desc .p-foot) แล้วแต่ละแถวคิดความกว้าง
 * ของตัวเองแยกกัน ไม่มีแถวไหนไปถ่วงแถวอื่น
 */
.product {
  display: grid;
  gap: 8px;
  padding: 16px 0;
  border-bottom: 1px solid var(--border);
}
.product:last-child { border-bottom: 0; }
.product h3 { margin: 0; font-size: 1.02rem; }
.product .price { font-weight: 700; font-size: 1.05rem; white-space: nowrap; }

/* ชื่อกินที่ทั้งหมดที่ราคาไม่ได้ใช้ — align-items: baseline ให้ตัวหนังสือสอง
   ขนาดนั่งบนเส้นเดียวกัน ไม่ใช่ลอยคนละระดับ */
.p-head { display: flex; align-items: baseline; gap: 12px; }
.p-head h3 { flex: 1 1 auto; min-width: 0; }
.p-head .price { flex: none; margin-left: auto; }

/* margin-left: auto ไม่ใช่ justify-content: space-between — สินค้าที่ไม่ได้นับ
   สต๊อกไม่มีป้ายคงเหลือ และ space-between ที่มีลูกตัวเดียวจะดันปุ่มไปชิดซ้าย */
.p-foot { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 12px; }
.p-foot .qty { margin-left: auto; }

.product .qty { display: flex; align-items: center; gap: 8px; }

/* จำนวนคงเหลือ ใช้สีเดียวกับป้ายสถานะออเดอร์ที่ผ่านเกณฑ์ contrast มาแล้ว
   ไม่ตั้งสีใหม่เอง — สีใหม่คือหนี้ที่ต้องไปวัด contrast ทั้งสองโหมดอีกรอบ */
.product .stock {
  font-size: .82rem; font-weight: 700;
  padding: 2px 9px; border-radius: 999px;
}
.product .stock.low { background: var(--warn-bg); color: var(--warn-text); }
.product .stock.out { background: var(--danger-bg); color: var(--danger); }

/*
 * คำอธิบายสินค้า — เต็มความกว้างการ์ด ตัดไว้สามบรรทัด
 *
 * `white-space: pre-line` เพราะช่องคำอธิบายในหน้าจัดการสินค้าเป็น <textarea>
 * และ text() ใน src/products.js แค่ trim() เท่านั้น เจ้าของร้านจึงพิมพ์ขึ้น
 * บรรทัดใหม่ได้อยู่แล้ว และหน้านี้เคยกลืนมันหายไปเงียบ ๆ ทั้งหมด
 *
 * `overflow-wrap: break-word` **ไม่ใช่ anywhere** — เหตุผลเดียวกับที่ .note
 * เขียนไว้: anywhere ให้เบราว์เซอร์ตัดที่ตัวอักษรไหนก็ได้ ซึ่งทำให้คำไทยแตก
 * เป็นหลายบรรทัดละสองตัวอักษร ส่วน break-word ตัดเฉพาะคำที่ยาวเกินกล่องจริง ๆ
 */
/* คำอธิบายกว้างเต็มแถว ส่วนปุ่มชิดซ้ายตามความยาวข้อความของมันเอง
 *
 * ถ้าใส่ justify-items: start ที่ตัวครอบ กล่องคำอธิบายจะหดเท่าข้อความ ซึ่งดู
 * เหมือนกันบนจอ แต่ทำให้ "กว้างเต็มการ์ดหรือยัง" วัดไม่ได้ และเทสต์ที่ล็อก
 * เรื่องนี้ไว้จะกลายเป็นเทสต์ความยาวข้อความแทนที่จะเป็นเทสต์เลย์เอาต์ */
.p-desc { display: grid; gap: 6px; }
.p-desc .more { justify-self: start; }

.desc {
  color: var(--muted);
  font-size: .88rem;
  line-height: 1.6;
  white-space: pre-line;
  overflow-wrap: break-word;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}
.desc.open {
  display: block;
  -webkit-line-clamp: unset;
  line-clamp: unset;
  overflow: visible;
}

/* ปุ่มโผล่เฉพาะเมื่อข้อความถูกตัดจริง (markClipped() ติด data-clipped ให้) หรือ
   เมื่อกางอยู่ ซึ่งต้องมีปุ่มไว้ย่อกลับ

   ปุ่มที่ขึ้นทั้งที่ไม่มีอะไรให้อ่านเพิ่ม คือปุ่มหลอก — กดแล้วไม่มีอะไรเกิดขึ้น
   ซึ่งแย่กว่าไม่มีปุ่ม */
.more {
  display: none;
  font: inherit;
  font-size: .85rem;
  font-weight: 700;
  color: var(--accent);
  background: none;
  border: 0;
  padding: 4px 0;
  /* เป้ากดเล็กกว่า 44px ได้ เพราะมันไม่ใช่ปุ่มที่กดผิดแล้วเสียเงิน — กดพลาด
     ก็แค่กางหรือย่อคำอธิบาย ต่างจากปุ่มเพิ่มจำนวนที่กดพลาดแล้วซื้อเกิน */
  min-height: 32px;
  cursor: pointer;
  text-decoration: underline;
}
.desc[data-clipped] ~ .more,
.desc.open ~ .more { display: inline-block; }
.more:hover { text-decoration: none; }

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

   คำอธิบาย (.desc) ไม่ถูกทำให้จางด้วย ทั้งที่ตอนแรกใส่ไว้ — มันใช้ --muted
   ซึ่งวัดได้ 5.43:1 บนพื้นการ์ดในโหมดสว่าง คือเหลือที่เหนือเกณฑ์ AA แค่
   0.93 การลดความทึบทับลงไปอีกจึงทำให้ตกเกณฑ์ทันที ไม่ว่าจะลดเท่าไร
   (ที่ 62% เหลือ 2.55:1) ส่วน h3 กับ .price ใช้ --text ที่ 16.4:1 จึงมีที่
   ให้จางได้จริง ที่ 75% ยังได้ 7.21:1

   และการจางคำอธิบายก็ไม่ได้ซื้ออะไรมาด้วย — ป้ายสีแดงกับราคาที่ถูกขีดฆ่า
   บอกว่าของหมดชัดอยู่แล้ว */
.product.soldout h3,
.product.soldout .price { opacity: .75; }
.product.soldout .price { text-decoration: line-through; }

/* Touch targets at 44px. Below that, a thumb on a phone misses often
   enough that people give up rather than retry. */
.qty button {
  width: 44px; height: 44px;
  font-size: 1.3rem; font-weight: 700;
  background: var(--surface-alt);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  cursor: pointer;
}
.qty button:hover:not(:disabled) { background: var(--border); }
.qty button:disabled { opacity: .4; cursor: not-allowed; }
.qty output { min-width: 2.2em; text-align: center; font-weight: 700; font-size: 1.05rem; }

/* ---------------------------------------------------------------- forms */

label { display: block; font-weight: 600; font-size: .9rem; margin-bottom: 6px; }
.field {
  width: 100%;
  /* 16px exactly: iOS Safari zooms the whole page in when a focused input
     is smaller, and the customer then has to pinch back out mid-address. */
  font: inherit; font-size: 16px;
  padding: 12px;
  background: var(--surface-alt);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  margin-bottom: 14px;
}
textarea.field { min-height: 88px; resize: vertical; }
.hint { color: var(--faint); font-size: .82rem; margin: -8px 0 14px; }

.btn {
  font: inherit; font-weight: 700;
  padding: 14px 20px;
  min-height: 48px;
  border-radius: 10px;
  border: 1px solid transparent;
  cursor: pointer;
}
.btn-primary { background: var(--brand); color: var(--on-brand); width: 100%; }
.btn-primary:disabled { opacity: .55; cursor: not-allowed; }
.btn-outline {
  background: var(--surface); color: var(--brand-text);
  border-color: var(--border-strong);
}
.btn-sm { padding: 8px 14px; min-height: 40px; font-size: .88rem; }

/* ---------------------------------------------------------------- totals */

.totals { border-top: 2px solid var(--border-strong); margin-top: 12px; padding-top: 12px; }
.row { display: flex; justify-content: space-between; gap: 16px; padding: 4px 0; }
.row .num { font-variant-numeric: tabular-nums; }
.row.grand { font-size: 1.25rem; font-weight: 800; padding-top: 10px; }
.row.ref { color: var(--muted); font-size: .88rem; }

/* ------------------------------------------------------------------- QR */

.pay {
  text-align: center;
  background: var(--surface);
  border: 2px solid var(--brand);
  border-radius: var(--radius);
  padding: 20px 16px;
}
/* The QR sits on its own white, always. A QR inverted by a dark theme
   fails to scan on a good number of readers, and a payment code that does
   not scan is the whole shop not working. */
.qr-frame {
  display: inline-block;
  background: #FFFFFF;
  padding: 12px;
  border-radius: 10px;
  margin: 8px 0;
  line-height: 0;
}
.qr-frame svg, .qr-frame img { width: min(260px, 70vw); height: auto; display: block; }

.amount {
  font-size: 2rem; font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--brand-text);
  margin: 6px 0 2px;
}
.amount-note { color: var(--muted); font-size: .85rem; }

.callout {
  background: var(--warn-bg);
  color: var(--warn-text);
  border-radius: 10px;
  padding: 12px 14px;
  font-size: .9rem;
  margin: 14px 0;
}
.callout strong { color: inherit; }

.err {
  background: var(--danger-bg); color: var(--danger);
  border-radius: 10px; padding: 12px 14px; margin: 12px 0; font-size: .92rem;
}

/* --------------------------------------------------------------- badges */

.badge {
  display: inline-block; font-size: .76rem; font-weight: 700;
  padding: 3px 10px; border-radius: 999px; white-space: nowrap;
}
.badge.AWAITING_PAYMENT { background: var(--warn-bg); color: var(--warn-text); }
.badge.PAID { background: var(--ok-bg); color: var(--ok); }
.badge.SHIPPED { background: var(--ok-bg); color: var(--ok); }
.badge.DONE { background: var(--surface-alt); color: var(--muted); }
.badge.CANCELLED { background: var(--danger-bg); color: var(--danger); }
.badge.EXPIRED { background: var(--surface-alt); color: var(--faint); }

/* ---------------------------------------------------------------- table */

/*
 * A table wider than the phone scrolls inside its own card.
 *
 * `position: relative` is not decoration — it is what keeps that scrolling
 * inside the card. The `.sr-only` labels in the table headers are
 * `position: absolute`, so their containing block is the nearest positioned
 * ancestor; with none, that is the page itself, and `overflow-x` cannot clip
 * a descendant whose containing block is outside it. The 1px spans therefore
 * sat at x = 471 and x = 618 in page coordinates and stretched the document
 * to 618px on a 360px screen — the whole page slid sideways to reveal
 * nothing at all, because the only thing out there was invisible by design.
 */
.scroll { overflow-x: auto; position: relative; }
table { border-collapse: collapse; width: 100%; font-size: .9rem; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); }
th { font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); white-space: nowrap; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }

/*
 * What the customer asked for, inside an order row.
 *
 * Not `.sub` like the phone number underneath a name: that styling says
 * "reference data, read it if you need it", and this is the opposite — an
 * instruction that decides whether the order goes out right. It borrows the
 * warn tokens, which already carry a dark-mode pair, so it stays readable
 * whichever way the phone is set.
 *
 * `white-space: pre-line` keeps the line breaks the customer typed; the
 * field is a textarea and people write addresses and lists in it.
 *
 * `overflow-wrap: break-word`, NOT `anywhere`. `anywhere` lets the browser
 * break at any character when the box is narrow, and inside a cramped table
 * column that turned "ทดสอบระบบ" into six lines of one or two letters each.
 * `break-word` only breaks a word that genuinely cannot fit, which is what
 * a long unbroken address needs and nothing else does.
 */
.note {
  margin-top: 6px;
  padding: 6px 9px;
  border-radius: 6px;
  background: var(--warn-bg);
  color: var(--warn-text);
  font-size: .85rem;
  line-height: 1.5;
  white-space: pre-line;
  overflow-wrap: break-word;
}
tbody tr:hover { background: var(--surface-alt); }

/* `.stats` เคยเป็นการ์ดสรุปเรียงเป็นกริด กฎชุดนั้นถูกลบออกเมื่อมันกลายเป็น
   บรรทัดเดียว — ดูกฎใหม่ในหัวข้อ "โต๊ะรับออเดอร์ — คิวงาน" ท้ายไฟล์
   การปล่อยกฎเก่าค้างไว้แปลว่ามี `.stats` สองชุดที่ขัดกันและตัวหนึ่งชนะเพราะ
   ลำดับในไฟล์ ซึ่งวันหลังมีคนจัดเรียงไฟล์ใหม่ก็พังเงียบ ๆ */

/* ------------------------------------------------- orders as cards */

/*
 * The order desk on a phone.
 *
 * A seven-column table on a 390px screen is not a layout problem to tune,
 * it is the wrong shape: the columns get so narrow that Thai, which has no
 * spaces to break at, wraps one character per line, and the amount — the
 * single number this whole shop is built around — gets cut off past the
 * right edge.
 *
 * So below 760px the same orders are drawn as cards instead, one per order,
 * laid out in the order the work actually happens: read the amount, find
 * the match, pack what it lists, send it where it says, press one button.
 */
.cards { display: grid; gap: 12px; }
.cards .empty { padding: 18px 2px; margin: 0; }

.ocard {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
  display: grid;
  gap: 10px;
}

.ocard-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }

/* The satang are drawn larger than the baht on purpose: two ฿120 orders
   differ in nothing a bank statement shows except those two digits. */
.ocard-amount { font-variant-numeric: tabular-nums; line-height: 1; }
.ocard-amount .b { font-size: 1.5rem; font-weight: 700; }
.ocard-amount .s { font-size: 1.9rem; font-weight: 800; color: var(--accent); }

.ocard-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: .85rem; }
.ocard-meta .code { font-weight: 700; letter-spacing: .02em; }
.ocard-meta .sub { margin: 0; }

.ocard-items { display: flex; flex-wrap: wrap; gap: 6px; }
.ocard-items .item,
td .item {
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: .85rem;
}
td .item { margin: 0 4px 4px 0; display: inline-block; }

.ocard-who { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; }
.ocard-who .name { font-weight: 600; }

.ocard-addr { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.ocard-addr .addr { color: var(--muted); font-size: .88rem; line-height: 1.6; overflow-wrap: break-word; }

.ocard-actions { display: flex; flex-wrap: wrap; gap: 8px; }
/* A finger, not a mouse: 44px is the smallest target that is reliably hit. */
.ocard-actions .btn { flex: 1 1 auto; min-height: 44px; }

.tel { color: var(--accent); text-decoration: none; font-variant-numeric: tabular-nums; }
.tel:hover { text-decoration: underline; }

.btn.copy { white-space: nowrap; min-height: 36px; }
.btn.copy.copied { border-color: var(--ok); color: var(--ok); }

/* ------------------------------------- collapsible section, product card */

/*
 * <summary> carries an <h2> so the heading stays a heading for screen
 * readers and the outline. The default marker is replaced because the
 * built-in triangle sits oddly next to a heading at this size.
 */
details > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
}
details > summary::-webkit-details-marker { display: none; }
details > summary h2 { margin: 28px 0 12px; }
details > summary::before {
  content: '▸';
  color: var(--muted);
  font-size: 1.1rem;
  margin-top: 14px;
  transition: transform .15s ease;
}
details[open] > summary::before { transform: rotate(90deg); }
details > summary:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 6px; }

.pcard label { display: block; margin: 10px 0 4px; font-size: .85rem; color: var(--muted); }
.pcard .field { margin: 0; }
.pcard .check { display: flex; align-items: center; gap: 8px; margin-top: 12px; font-size: .95rem; color: inherit; }
.pcard .check input { width: 20px; height: 20px; }

/* A product that is not for sale should read as switched off at a glance,
   without becoming so faint that its own price is hard to check. */
.pcard.off { border-style: dashed; }
.pcard.off .ocard-amount { opacity: .65; }

/* ------------------------------------------- which one the screen gets */

.wide-only { display: none; }

@media (min-width: 760px) {
  /* Wide enough for the table to breathe, and scanning fifty orders at once
     is genuinely easier in rows than in cards.
     
     Only `.narrow-only` disappears, not every `.cards` list. The product
     page is cards at every width because it has no table version — hiding
     all of them here once made that page blank on a desktop. */
  .wide-only { display: block; }
  .cards.narrow-only { display: none; }
}

.actions { display: flex; flex-wrap: wrap; gap: 6px; }

@media (max-width: 560px) {
  .wrap { padding: 16px 12px 48px; }
  h1 { font-size: 1.3rem; }
  .amount { font-size: 1.7rem; }
}

/* ------------------------------------------------- หน้าติดตามออเดอร์ */

.track-state { margin-bottom: 18px; }
.track-state .sub { margin: 10px 0 0; }

/* ขั้นตอนทั้งสี่ — ลูกค้าที่โอนเงินไปแล้วอยากรู้ว่าเหลืออีกกี่ขั้น ไม่ใช่แค่
   ว่าตอนนี้อยู่ตรงไหน คำตอบแรกทำให้รอได้ คำตอบหลังยังทิ้งให้เดา */
.steps { list-style: none; margin: 0; padding: 0; }
.step {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 0;
  font-size: .95rem;
}
.step .mark {
  width: 22px; text-align: center;
  font-size: 1rem; font-weight: 700;
  flex: none;
}
.step.done { color: var(--ok); }
.step.now  { color: var(--text); font-weight: 700; }
/* ขั้นที่ยังไม่ถึงใช้ --muted ไม่ใช่ opacity — ตัวจางด้วย opacity ทับสีที่
   ผ่านเกณฑ์มาแล้วจะตกเกณฑ์ทันที เหมือนที่เจอมากับคำอธิบายสินค้าที่หมด */
.step.todo { color: var(--muted); }

.ocard-track {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap;
  margin-top: 10px;
}
.ocard-track .track {
  font-size: .9rem;
  overflow-wrap: break-word;
  min-width: 0;
}
.ocard-notify { margin-top: 10px; }
/* ปุ่มนี้เป็นงานที่ทำต่อจากการกดเปลี่ยนสถานะ จึงกว้างเต็มการ์ดให้กดง่ายด้วย
   นิ้วโป้งข้างเดียว เหมือนปุ่มเปลี่ยนสถานะที่อยู่เหนือมัน */
.ocard-notify .btn { width: 100%; }

/* เวลาที่แต่ละขั้นเกิดขึ้น — ชิดขวา เพื่อให้ไล่ตาลงมาเป็นคอลัมน์เดียวได้
   ใช้ --muted ไม่ใช่ opacity ตามเหตุผลที่ .step.todo เขียนไว้ข้างบน */
.step .lb { flex: 1 1 auto; min-width: 0; }
.step .at {
  flex: none;
  color: var(--muted);
  font-size: .82rem;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* แถวล่างสุด — เวลาที่ดึงข้อมูลมา กับปุ่มขอของสด */
.fresh {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 8px 12px;
  margin-top: 14px;
}
.fresh .sub { margin: 0; font-size: .85rem; }
.fresh .btn { flex: none; }

/*
 * ป้ายบอกว่าเพิ่งมีอะไรเปลี่ยน
 *
 * ใช้โทเคนชุด --ok เพราะข่าวที่มาถึงตรงนี้เป็นข่าวดีแทบทุกครั้ง (ได้เงินแล้ว
 * ส่งของแล้ว ปิดออเดอร์แล้ว) ส่วนการยกเลิกกับหมดเวลาเห็นได้จากป้ายสถานะที่
 * เปลี่ยนสีอยู่แล้ว การมีสีสองชุดตรงนี้จะแข่งกับป้ายสถานะเปล่า ๆ
 */
.changed-note {
  margin: 0 0 12px;
  padding: 10px 14px;
  border-radius: var(--radius);
  background: var(--ok-bg);
  color: var(--ok);
  font-weight: 700;
  font-size: .92rem;
}

/* ไฮไลต์การ์ดสถานะสั้น ๆ ให้ตาไปหาที่ถูกที่ — ป้ายข้างบนบอกว่าเปลี่ยนอะไร
   เส้นนี้บอกว่าไปดูตรงไหน */
#stateCard.changed { border-color: var(--ok); }

.track-no { font-variant-numeric: tabular-nums; letter-spacing: .02em; }
#trackBody .btn { width: 100%; margin-top: 12px; }
.foot { margin-top: 24px; text-align: center; }

/* ============================================ โต๊ะรับออเดอร์ — คิวงาน */

/*
 * แถบบนสุด เหนียวไว้
 *
 * ที่ร้อยใบ ถ้าไม่เหนียว พอเลื่อนลงไปกลางคิวแล้วอยากสลับไปดูอีกคิวหรืออยาก
 * ค้นหา ต้องเลื่อนกลับขึ้นมาสุดก่อนทุกครั้ง ซึ่งเป็นการเลื่อนหาแบบเดียวกับที่
 * หน้านี้มีไว้เพื่อเลิกทำ
 */
.deskbar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: grid;
  gap: 10px;
  padding: 10px 0;
  margin: 8px 0 16px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

/*
 * แท็บอยู่บรรทัดเดียว เลื่อนซ้ายขวาได้ ไม่ตัดขึ้นบรรทัดใหม่
 *
 * สี่แท็บที่ตัดบรรทัดบนจอ ๓๙๐px กินสองบรรทัด และมันอยู่ในแถบ sticky จึงกิน
 * ตลอดเวลา ไม่ใช่แค่ตอนอยู่บนสุด การเลื่อนแท็บด้วยนิ้วเป็นท่าที่คนใช้มือถือ
 * ทำอยู่แล้ว ต่างจากการเลื่อนหาออเดอร์ในรายการยาว ซึ่งเป็นสิ่งที่หน้านี้แก้
 */
.tabs {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  /* ไม่ให้กล่อง flex ยืดตามลูกจนดันหน้าเว็บกว้างเกินจอ — min-width ปริยาย
     ของ flex item คือ auto ซึ่งแปลว่า "เท่าเนื้อหา" และนั่นทำให้ทั้งหน้า
     เลื่อนซ้ายขวาแทนที่จะเลื่อนแค่แถบแท็บ */
  min-width: 0;
  scrollbar-width: none;
  /* ให้แท็บสุดท้ายไม่ติดขอบพอดีจนดูเหมือนหมดแล้ว */
  padding-right: 4px;
}
.tabs::-webkit-scrollbar { display: none; }
.tab { flex: none; }

.tab {
  font: inherit;
  font-weight: 700;
  font-size: .9rem;
  display: flex;
  align-items: center;
  gap: 7px;
  /* นิ้วโป้ง ไม่ใช่เมาส์ — 44px คือเป้าที่เล็กที่สุดที่กดโดนทุกครั้ง */
  min-height: 44px;
  padding: 6px 13px;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
}
.tab[aria-pressed="true"] {
  border-color: var(--accent);
  /* เส้นขอบสองชั้นแทนการถมสีทั้งปุ่ม ถมสีแล้วต้องไปหาสีตัวอักษรที่ผ่าน
     contrast บนพื้นนั้นทั้งสองโหมด ชั้นนี้ไม่แตะสีตัวอักษรเลย */
  box-shadow: inset 0 0 0 1px var(--accent);
}
.tab .n {
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-size: .85rem;
}
.tab[aria-pressed="true"] .n { color: var(--accent); }

/* จำนวนใบที่เลยกำหนดในคิวนั้น เห็นได้จากทุกแท็บ ไม่ต้องกดเข้าไปดูทีละคิว */
.tab .dot {
  min-width: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--danger-bg);
  color: var(--danger);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.deskbar-tools { display: flex; gap: 8px; align-items: center; min-width: 0; }
/* ช่องค้นหาอยู่ในแถว ไม่ใช่ย่อหน้าของตัวเอง จึงไม่เอา margin ล่างของ .field */
.field.search { margin-bottom: 0; flex: 1 1 auto; min-width: 0; padding: 9px 12px; }
.deskbar-tools .btn { flex: none; }

/* จอกว้างพอ: แท็บกับช่องค้นหาอยู่บรรทัดเดียว แถบ sticky เตี้ยลงครึ่งหนึ่ง
   จึงเห็นออเดอร์มากขึ้นต่อหนึ่งหน้าจอ */
@media (min-width: 760px) {
  .deskbar { grid-template-columns: auto minmax(220px, 1fr); align-items: center; }
  .deskbar-tools { max-width: 420px; justify-self: end; }
}

/*
 * ตัวเลขเงินเป็นบรรทัดเดียว ไม่ใช่การ์ด
 *
 * ตอนเป็นการ์ดสองใบมันกินร้อยแปดสิบพิกเซลบนจอ ๓๙๐px ดันออเดอร์ใบแรกลงไปที่
 * ๕๔๐px ทั้งที่มันเป็นข้อมูลอ้างอิง ไม่ใช่งานที่ต้องลงมือทำ
 */
.stats {
  display: flex; flex-wrap: wrap; gap: 4px 18px;
  margin: 0 0 14px;
  font-size: .85rem; color: var(--muted);
}
.stats .st b {
  color: var(--text); font-weight: 800;
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------- ตัวคิวเอง */

.queues { display: grid; gap: 22px; align-items: start; }
/* `display: grid` ชนะ `[hidden]` ของเบราว์เซอร์ ถ้าไม่เขียนบรรทัดนี้ คิวจะยัง
   โผล่อยู่ใต้ผลการค้นหาทั้งที่สั่งซ่อนไปแล้ว */
.queues[hidden] { display: none; }

.queue > h2 { margin: 0 0 4px; display: flex; align-items: baseline; gap: 8px; }
.queue > h2 .n {
  font-size: .9rem; font-weight: 700;
  color: var(--muted); font-variant-numeric: tabular-nums;
}
.qnote { margin: 0 0 10px; font-size: .85rem; }
.qlist { display: grid; gap: 10px; }
.qlist .empty { padding: 14px 2px; margin: 0; }

/*
 * ความกว้างเป็นคนตัดสินว่าเห็นกี่คิว ไม่ใช่ JavaScript
 *
 * คิวทั้งสี่ถูกวาดลง DOM เสมอ ที่นี่เลือกว่าอันไหนโผล่ ทางเลือกอีกทางคือให้ JS
 * คอยฟัง resize และฟังการหมุนจอ แล้ววันหนึ่งจะพลาดสักอัน
 */
#queues[data-show="money"]   .queue:not([data-queue="money"]),
#queues[data-show="pack"]    .queue:not([data-queue="pack"]),
#queues[data-show="close"]   .queue:not([data-queue="close"]),
#queues[data-show="history"] .queue:not([data-queue="history"]) { display: none; }

/* จอกว้างพอ: คิวงานสามอันอยู่ในสายตาพร้อมกัน ไม่ต้องสลับแท็บไปมาระหว่าง
   ไล่ยอดกับแพ็คของ ส่วนประวัติยังสลับไปเต็มความกว้างเหมือนเดิม */
@media (min-width: 1000px) {
  #queues:not([data-show="history"]) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  #queues:not([data-show="history"]) .queue[data-queue="money"],
  #queues:not([data-show="history"]) .queue[data-queue="pack"],
  #queues:not([data-show="history"]) .queue[data-queue="close"] { display: block; }
  #queues:not([data-show="history"]) .queue[data-queue="history"] { display: none; }
}

/* ------------------------------------------------------ แถวกระชับ */

/*
 * หนึ่งออเดอร์เป็นแถวที่กางออกได้
 *
 * หุบอยู่ = มีแต่สิ่งที่ใช้ "หา" ใบนั้น กางออก = ครบเท่าการ์ดเต็ม ใช้ <details>
 * ของเบราว์เซอร์ตรง ๆ จึงได้การกดด้วยคีย์บอร์ดและการอ่านด้วย screen reader
 * มาฟรี ไม่ต้องเขียนกลไกกาง/หุบเองให้ต้องมาดูแล
 */
.orow {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--radius);
}
.orow > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 10px;
  padding: 10px 12px;
}
.orow > summary::-webkit-details-marker { display: none; }
.orow > summary::before { content: none; }
.orow > summary:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: var(--radius); }

.orow .rowmain {
  flex: 1 1 210px;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
}
.orow .rowbtns { display: flex; flex-wrap: wrap; gap: 6px; }

/* สตางค์ใหญ่กว่าบาทโดยตั้งใจ ออเดอร์ ฿120 สองใบต่างกันทุกอย่างยกเว้นสองหลัก
   นั้น และสองหลักนั้นคือสิ่งเดียวที่สลิปธนาคารบอก */
.orow .amount { font-variant-numeric: tabular-nums; line-height: 1.1; white-space: nowrap; }
.orow .amount .b { font-size: 1.15rem; font-weight: 700; }
.orow .amount .s { font-size: 1.45rem; font-weight: 800; color: var(--accent); }
.orow .amount.sm { font-size: .95rem; font-weight: 700; }

.orow .rowid { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; min-width: 0; }
.orow .rowid .code { font-size: .85rem; letter-spacing: .02em; white-space: nowrap; }
.orow .rowid .nm { font-size: .9rem; color: var(--muted); overflow-wrap: break-word; min-width: 0; }
.orow .track-no { font-size: .85rem; color: var(--muted); overflow-wrap: break-word; min-width: 0; }
.orow .sub { margin: 0; font-size: .82rem; }

.orow-body {
  display: grid;
  gap: 10px;
  padding: 0 12px 12px;
  border-top: 1px solid var(--border);
  margin-top: 2px;
  padding-top: 12px;
}

/* เส้นขอบซ้ายคือป้ายที่อ่านได้โดยไม่ต้องอ่าน — ไล่ตาลงมาทั้งคิวก็เห็นว่าใบไหน
   ค้างนาน โดยไม่ต้องหยุดอ่านข้อความบนป้าย */
.orow.warn { border-left-color: var(--warn-text); }
.orow.late { border-left-color: var(--danger); }

.urg {
  font-size: .76rem; font-weight: 700;
  padding: 2px 9px; border-radius: 999px; white-space: nowrap;
}
.urg.warn { background: var(--warn-bg); color: var(--warn-text); }
.urg.late { background: var(--danger-bg); color: var(--danger); }

/* ข้อมูลจัดส่งในหน้าโอนเงิน — แบบย่อ ส่วนเต็มอยู่ที่ /o/CODE */
.shipbox {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.shipbox .btn { width: 100%; margin-top: 10px; }
