/* ============================================================================
   PTCARGO · shared/css/layout.css   (Design System · Layer 2 of 4)
   ----------------------------------------------------------------------------
   Structure only — containers, grids, and the primitives that arrange things.
   Uses --space-* / --radius-* tokens ONLY. No brand colors and no buttons here
   (those live in components.css). The one exception the work-order allows:
   .card / .panel may carry a surface background + hairline + shadow token.
   Requires tokens.css to be loaded first.   Phase 1 does NOT touch any .html.
   ========================================================================== */

/* ---- page container ------------------------------------------------------ */
/* ---- base typography ----------------------------------------------------- *
 * ★ ฟอนต์ตั้งต้นของทั้งหน้า ★ เดิมทุกหน้าประกาศ body{font-family:var(--fb)} เองในไฟล์
 * CSS ของหน้านั้น ⇒ หน้าที่ไม่มีไฟล์ของตัวเองตกไปใช้ฟอนต์ปริยายของเบราว์เซอร์
 * (Times New Roman) ทั้งหน้า — ไม่มี error ให้เห็น เห็นได้ด้วยตาเท่านั้น
 * ตั้งเฉพาะ font-family อย่างเดียว ไม่แตะสี/พื้นหลัง เพราะแต่ละระบบมีผืนสีของตัวเอง
 * และไฟล์ของหน้าโหลดทีหลังเสมอ จึงทับค่านี้ได้ตามเดิม
 * -------------------------------------------------------------------------- */
body { font-family: var(--fb, 'Prompt', sans-serif); }

/* ---- page container ------------------------------------------------------ */
.container {
  width: 100%;
  max-width: 1120px;
  margin-inline: auto;
  padding-inline: var(--space-4);
}
.container-narrow { max-width: 760px; }
.container-wide   { max-width: 1360px; }

/* Member/mobile content frame. A phone viewport is naturally at most 430px;
   desktop AppShell must keep the full content column instead of simulating a phone. */
.member-frame,
.phone {
  width: 100%;
  max-width: 430px;
  margin-inline: auto;
}
@media (min-width: 768px) {
  body.ptshell .member-frame,
  body.ptshell .phone {
    max-width: none;
    margin-inline: 0;
  }
}

/* Shared auth frame; replaces the byte-identical inline block formerly copied
   into every auth document. All supported auth pages contain .authbg or .page. */
@media (min-width: 480px) {
  html:has(body .authbg), html:has(body > .hero .crest), html:has(body > .stage #slide1), html:has(body input#cur) { background: #e7e0d7; }
  body:has(.authbg), body:has(> .hero .crest), body:has(> .stage #slide1), body:has(input#cur) { max-width: 430px !important; margin-left: auto !important; margin-right: auto !important; min-height: 100vh; box-shadow: 0 0 46px -12px rgba(45,28,6,.34); }
  body:has(.authbg) :is(.actbar,.pybar,.act,.savebar,.foot,.adjbar,.bnav,.bar-cta,.asheet),
  body:has(> .hero .crest) :is(.actbar,.pybar,.act,.savebar,.foot,.adjbar,.bnav,.bar-cta,.asheet),
  body:has(> .stage #slide1) :is(.actbar,.pybar,.act,.savebar,.foot,.adjbar,.bnav,.bar-cta,.asheet),
  body:has(input#cur) :is(.actbar,.pybar,.act,.savebar,.foot,.adjbar,.bnav,.bar-cta,.asheet) {
    left: calc(50% - 215px) !important; right: auto !important; width: 100% !important; max-width: 430px !important;
  }
  body:has(.authbg) .fab, body:has(> .hero .crest) .fab, body:has(> .stage #slide1) .fab, body:has(input#cur) .fab { right: calc(50% - 207px) !important; left: auto !important; }
}

/* ============================================================================
   หน้า auth บนแท็บเล็ต/เดสก์ท็อป (2026-09-10)
   ----------------------------------------------------------------------------
   ★ ปัญหาเดิม ★ กฎ body:has(.authbg) ด้านบนบีบทั้งหน้าเหลือ 430px ตั้งแต่จอ 480px
   ขึ้นไป และใส่เงาเป็นกรอบ ⇒ บนจอ 1440px หน้าเข้าสู่ระบบกลายเป็นแถบขนาดมือถือ
   ลอยอยู่กลางพื้นสีส้ม ดูเหมือนหน้าที่ยังไม่ได้ออกแบบสำหรับเดสก์ท็อป

   หน้า auth ต่างจากหน้าอื่นตรงที่ ★ ไม่มีแถบนำทาง ไม่มีรายการยาว ★ มีแค่การ์ดเดียว
   จึงไม่ต้องการกรอบโทรศัพท์ — ปล่อยให้พื้นหลังแบรนด์เต็มจอแล้วจัดการ์ดไว้กลาง
   คือรูปแบบมาตรฐานของหน้าเข้าสู่ระบบบนจอใหญ่

   แก้เฉพาะสาย .authbg เท่านั้น — อีกสามสาย (.hero .crest / .stage #slide1 /
   input#cur) เป็นคนละหน้าและยังต้องการกรอบเดิม จึงไม่แตะ
   ============================================================================ */
@media (min-width: 768px) {
  html:has(body .authbg) { background: none; }
  body:has(.authbg) {
    max-width: none !important;
    margin: 0 !important;
    box-shadow: none !important;
  }
  /* .authbg เป็น flex จัดกลางอยู่แล้ว — ให้พื้นที่หายใจมากขึ้นบนจอใหญ่ */
  body:has(.authbg) .authbg { padding: 56px 24px; }
  body:has(.authbg) .authbg > .page { max-width: 468px; }
  /* การ์ดบนจอใหญ่: กว้างขึ้น หายใจมากขึ้น และยกตัวด้วยเงาที่ลึกกว่าเดิม */
  body:has(.authbg) .authbg > .page > .card { padding: 34px 32px; border-radius: 20px; }
}

@media (min-width: 1180px) {
  /* จอกว้างมาก: ขยายวงแสงพื้นหลังให้เต็มพื้นที่ ไม่ให้พื้นสีทึบดูว่างเปล่า
     (.glow มีอยู่ในมาร์กอัปของทุกหน้า auth แล้ว — ไม่ต้องเพิ่ม element) */
  body:has(.authbg) .authbg > .glow { transform: scale(2.2); }
  body:has(.authbg) .authbg > .page { max-width: 500px; }
  body:has(.authbg) .authbg > .page > .card { padding: 40px 38px; }
}

/* จอเตี้ย (แล็ปท็อปแนวนอน / แท็บเล็ตแนวนอน) — ลดช่องว่างบนล่างไม่ให้ต้องเลื่อน */
@media (min-width: 768px) and (max-height: 760px) {
  body:has(.authbg) .authbg { padding: 28px 24px; }
  body:has(.authbg) .authbg > .page > .card { padding: 26px 30px; }
}

/* ---- grid ---------------------------------------------------------------- */
.grid {
  display: grid;
  gap: var(--space-4);
}
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid-auto { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }

/* ---- flow rows / columns ------------------------------------------------- */
.row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}
.col {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* ---- stack (vertical rhythm) & cluster (inline group) -------------------- */
.stack   { display: flex; flex-direction: column; gap: var(--space-3); }
.stack-sm { gap: var(--space-2); }
.stack-lg { gap: var(--space-5); }

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* ---- centering ----------------------------------------------------------- */
.center {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ---- toolbar (title left, actions right) --------------------------------- */
.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: var(--space-2);
}

/* ---- sidebar + content --------------------------------------------------- */
.sidebar {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
}

/* ---- surfaces: card & panel (surface bg + line + shadow tokens allowed) --- */
.card {
  background: var(--color-surface);          /* white (#fff) — ONE card look system-wide */
  border: 1px solid var(--color-line);
  border-radius: var(--radius-lg, 20px);     /* Owner card spec 2026-07-18: rounded 20px */
  box-shadow: var(--shadow-md);
  padding: var(--sp-card-pad, 16px);         /* CLASS_MAP §B — inner card padding, single source */
}
.panel {
  background: var(--color-surface-2);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}
.card-flush { padding: 0; }

/* ---- responsive: collapse multi-column layouts on small screens ---------- */
@media (max-width: 720px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
  .sidebar { grid-template-columns: 1fr; }
}

/* ============================================================================
   CANONICAL VOCABULARY — page skeleton + structure (CLASS_MAP 2026-07-18)
   ----------------------------------------------------------------------------
   The Owner-defined class names every page uses system-wide. Added here (folded
   from the retired shared/css/pt-layout.css pilot + CLASS_MAP §A/§B) so there is
   ONE source. Spacing flows through the --sp-* tokens. The existing rules above
   (.container/.grid/.row/.col/.card/.panel/.stack/…) are KEPT unchanged so the
   55 pages already loading this file are not disturbed.

   TOKEN NOTE: the page-skeleton rules below (header.hd/.title/.pybar/.hero*)
   read the LEGACY alias tokens (--line/--ink/--fd/--paper/--sun/--clay/…) that
   the member/mobile pages theme in their own :root — this keeps the pilot
   (account-hub) byte-identical to the retired pt-layout.css and lets each page's
   theme flow through. tokens.css maps every legacy alias to a --color-* default.
   ============================================================================ */

/* ---- page header bar  (folded from pt-layout header.hd) -------------------
   Scoped to header.hd DELIBERATELY: nested sheet headers use <div class="hd">
   and must NOT inherit sticky/blur/border chrome. Base skeleton header is always
   <header class="hd">. Only account-hub uses the compound form today, so this
   selector cannot affect the other shared-CSS pages (they use bare <header>).   */
header.hd {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 10px;
  padding: 11px 12px;
  background: rgba(255, 248, 242, .92);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line, #f2e6d8);
}

/* ---- .page — page content wrapper (was .wrap) · outer page padding -------- */
.page { padding: var(--sp-page, 16px); margin-bottom: 35px; }

/* ---- uniform vertical rhythm between skeleton blocks (CLASS_MAP §B) --------
   THE mechanism that makes "ช่องว่างเท่ากันทั้งระบบ" real: every .card that
   follows a sibling inside main.page gets the SAME gap from the single --sp-card
   token. Scoped to `main.page >` so it only governs skeleton-conformant pages
   (the ones we convert) and never disturbs cards nested in .stack/.grid/.sidebar
   layouts on the 55 legacy design-system pages. First block sits flush to the
   .page padding. Pages MUST NOT set their own margin/padding on .page/.card —
   spacing flows from here only.                                                */
main.page > * + .card { margin-top: var(--sp-card, 14px); }
main.page > .card:first-child { margin-top: 0; }

/* ---- same rhythm inside the two-column wrappers ---------------------------
   .mainc / .rcol are the shared two-column convention (main column + sticky
   right rail). Cards there sit ONE level deeper, so the `main.page >` rule
   above — a direct-child selector by design — never matches them and the
   cards stack flush at 0px. Measured in a real browser across 112 admin
   pages at 1440/1280/900: 3 hit this (content-settings, attendance-review,
   engage). Kept to these two class names on purpose, so the deliberate
   exclusion of .stack/.grid/.sidebar nesting on the legacy pages still
   holds, and reusing --sp-card so the gap matches every other page.
   Guarded by tests/browser/admin-card-rhythm.spec.js — grep cannot catch
   this class of bug because it depends on the cascade, not on file text. */
main.page .mainc > * + .card,
main.page .rcol  > * + .card { margin-top: var(--sp-card, 14px); }
main.page .mainc > .card:first-child,
main.page .rcol  > .card:first-child { margin-top: 0; }

/* ---- .title — page / section title (was .sechd / htitle / st) ------------- */
.title {
  display: flex; align-items: center; gap: 7px;
  margin: 0 0 11px;
  font-family: var(--fd, 'Mitr', sans-serif);
  font-weight: 600; font-size: 14px;
  color: var(--ink, #2a2016);
}

/* ---- .pybar — fixed bottom action bar (folded from pt-layout) -------------
   Mobile = fixed to the viewport foot. On desktop the AppShell neutralises the
   fixed position so the bar flows inline beside the sidebar (the two cooperate). */
.pybar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  display: flex; align-items: center; gap: var(--sp-gap, 8px);
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  background: var(--paper, #fff);
  border-top: 1px solid var(--line, #f2e6d8);
  box-shadow: 0 -8px 24px -16px rgba(120, 70, 20, .4);
}

/* ---- .hero + variants — full-width top banner (CLASS_MAP §6.5) ------------
   base = structure only (relative + clip + padding); the variant carries the
   fill + white text. Full-bleed by DOM placement (put the hero OUTSIDE .page's
   padding), matching the existing member/mobile hero pattern.                  */
.hero {
  position: relative;
  overflow: hidden;
  padding: 22px 16px 24px;
}
.hero1, .hero2, .hero3 { color: #fff; }
.hero1 { background: linear-gradient(120deg, var(--sun, #ff7a1a), var(--sun-deep, #ef5f06)); }        /* standard orange */
.hero2 { background: linear-gradient(120deg, var(--clay, #c8692b), var(--clay-deep, #a9531f)); }      /* coffee / member  */
.hero3 { background: linear-gradient(120deg, var(--ember, #ff3d2e), var(--red-d, #b03a30)); }         /* flash / hot      */

/* ---- 8-slot proportional column spans (used inside a flex .row) -----------
   .col-N shares a .row proportionally (N of 8). Pairs with the existing flex
   .row above. min-width:0 keeps long content from overflowing.                 */
.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8 { min-width: 0; }
.col-1 { flex: 1 1 0; }
.col-2 { flex: 2 1 0; }
.col-3 { flex: 3 1 0; }
.col-4 { flex: 4 1 0; }
.col-5 { flex: 5 1 0; }
.col-6 { flex: 6 1 0; }
.col-7 { flex: 7 1 0; }
.col-8 { flex: 8 1 0; }
/* responsive class-kit (Owner 2026-07-18): mobile = each column stacks full-width;
   desktop (>640px) = proportional side-by-side. So `.col-8 + .col-4` = 2-col 66/33 and
   `.col-4 ×3` = 3 equal cols on desktop, all stacked on phones. Author picks widths by N. */
@media (max-width: 640px) {
  .col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8 { flex-basis: 100%; }
}

/* ============================================================================
   DESKTOP KIT (Owner 2026-07-18) — "awesome kit": one shared source, every page
   auto-improves on wide screens. (a) buttons stop being full-width blocks;
   (b) opt-in multi-column page layout.
   ============================================================================ */
@media (min-width: 1024px) {
  /* (a) Buttons size to their content on desktop (mobile keeps full-width CTAs).
     High specificity so it beats page-local `.btn{width:100%;display:flex}`.
     Opt back into full-width with .block / .btn-block (e.g. a form submit).      */
  main.page .btn:not(.block):not(.btn-block):not(.full),
  main.page .button:not(.block):not(.btn-block):not(.full) {
    display: inline-flex;
    width: auto;
    align-self: flex-start;
  }

  /* (b) Opt-in desktop multi-column content: <main class="page cols2"> (or cols3).
     Cards auto-flow into columns; grid gap owns spacing; a full-width block uses
     .card.wide, and a hero / a section heading (.title as a direct child) spans
     all columns. Mobile stays single-column (this whole block is desktop-only).  */
  main.page.cols2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-card, 14px); align-items: start; }
  main.page.cols3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-card, 14px); align-items: start; }
  main.page.cols2 > .card, main.page.cols3 > .card { margin-top: 0; }
  main.page.cols2 > .card.wide, main.page.cols3 > .card.wide,
  main.page.cols2 > .hero,      main.page.cols3 > .hero,
  main.page.cols2 > .title,     main.page.cols3 > .title { grid-column: 1 / -1; }
}

/* Extend the button-de-stretch below 1024 for the app-shell desktop (Owner 2026-07-21):
   from 768px up, buttons on real desktop (body.ptshell) size to their content instead of
   staying full-width mobile bars. Scoped to body.ptshell so phone-frame pages are NOT
   affected. Mobile (<768) keeps full-width CTAs. Opt back into full-width with
   .block / .btn-block / .full (e.g. a form submit that should fill its card).            */
@media (min-width: 768px) {
  body.ptshell main.page .btn:not(.block):not(.btn-block):not(.full),
  body.ptshell main.page .button:not(.block):not(.btn-block):not(.full) {
    display: inline-flex;
    width: auto;
    align-self: flex-start;
  }
}

/* ---- .nav — horizontal in-content nav / pill scroller (was navrow) -------- */
.nav {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* ---- typography classes (headings + body as classes) --------------------- */
.h1 { font-family: var(--fd, 'Mitr', sans-serif); font-weight: 700; font-size: var(--font-2xl, 26px); line-height: var(--line-tight, 1.25); margin: 0; color: var(--ink); }
.h2 { font-family: var(--fd, 'Mitr', sans-serif); font-weight: 600; font-size: var(--font-xl, 20px);  line-height: var(--line-tight, 1.25); margin: 0; color: var(--ink); }
.h3 { font-family: var(--fd, 'Mitr', sans-serif); font-weight: 600; font-size: var(--font-lg, 16px);  line-height: var(--line-tight, 1.25); margin: 0; color: var(--ink); }
.h4 { font-family: var(--fd, 'Mitr', sans-serif); font-weight: 600; font-size: var(--font-md, 14px);  line-height: var(--line-tight, 1.25); margin: 0; color: var(--ink); }
.h5 { font-family: var(--fd, 'Mitr', sans-serif); font-weight: 600; font-size: var(--font-sm, 13px);  line-height: var(--line-tight, 1.25); margin: 0; color: var(--ink); }
.h6 { font-family: var(--fd, 'Mitr', sans-serif); font-weight: 600; font-size: var(--font-xs, 11px);  line-height: var(--line-tight, 1.25); margin: 0; color: var(--ink); letter-spacing: .04em; text-transform: uppercase; }
.p  { font-family: var(--fb, 'Prompt', sans-serif); font-size: var(--font-md, 14px); line-height: var(--line-normal, 1.5); color: var(--ink); margin: 0 0 var(--space-3); }

/* ============================================================================
   CLASS_MAP additions (2026-07-18b) — ADDITIVE ONLY (track-parcel pilot)
   คลาสใหม่ตาม vocab (+เลข) · ไม่แก้กฎเดิม → 55 หน้าไม่กระทบ · token-driven
   ============================================================================ */
/* hero4 — hero การ์ดพื้นสว่าง (ต่างจาก .hero1-3 ที่เป็นพื้นสี) */
.hero4 { background: var(--color-surface); border: 1px solid var(--color-line); border-radius: var(--radius-lg); box-shadow: var(--shadow-md); padding: var(--space-6); color: var(--color-text); }
/* steps — แถว process (ไอคอน+ข้อความ) */
.steps {grid-template-columns: repeat(2, minmax(0,1fr));gap: var(--space-2);}
.step {
    display: flex;
    gap: 13px;
    padding: 13px 0px 13px 0px;
    border-bottom: 1px dashed var(--line);
    animation: pop .4s ease both;
}
.step .step-ic { width: 44px; height: 44px; border-radius: var(--radius-md); display: grid; place-items: center; margin: 0 auto var(--space-2); background: var(--color-primary-soft); color: var(--color-primary); }
.step .step-ic svg { width: 22px; height: 22px; }
.step b { font-family: var(--font-display, 'Mitr', sans-serif); font-weight: 600; font-size: var(--font-sm, 13px); display: block; line-height: 1.3; color: var(--color-text); }
/* ★ 2026-07-29 — คำอธิบายใต้หัวข้อในแต่ละขั้นตอน
   ของเดิม: color:#fff + text-align:center + font-size fallback 20px
   ปัญหา: .step เป็นแถวแนวนอน (เลข + ข้อความ) บนการ์ดพื้นขาว — ตัวหนังสือสีขาว
   จึงมองไม่เห็น และการจัดกึ่งกลางทำให้บรรทัดคำอธิบายไม่ตรงกับหัวข้อด้านบน
   ร่องรอยว่าเป็นของเสียมานาน: kyc-verify.css / track-parcel.css เขียนคอมเมนต์
   ไว้ว่าต้องเขียนทับ `.step span{color:#fff}` เพราะทำให้ข้อความหาย
   และไฟล์โมดูล 6 ตัวในกลุ่ม shipping ก็เขียนทับ color/font-size ทิ้งไว้เหมือนกัน
   ★ fallback 20px ของ --font-xs ก็ผิด — xs ต้องเล็กกว่า sm(13px) ไม่ใช่ใหญ่กว่า */
.step span {font-size: var(--font-xs, 11.5px);color: var(--color-text-soft, #6E5C4C);line-height: 1.6;display: block;margin-top: 3px;text-align: left;}
@media (min-width: 720px) { .steps { grid-template-columns: repeat(5, minmax(0,1fr)); } }
/* timeline — ไทม์ไลน์สถานะแนวตั้ง */
.timeline { display: flex; flex-direction: column; }
.tl-item { display: flex; gap: var(--space-3); padding-bottom: var(--space-4); position: relative; }
.tl-item:last-child { padding-bottom: 0; }
.tl-item .tl-dot { width: 26px; height: 26px; border-radius: 50%; flex: none; display: grid; place-items: center; color: #fff; background: var(--color-line-strong); z-index: 1; }
.tl-item .tl-dot svg { width: 14px; height: 14px; }
.tl-item.is-done .tl-dot { background: var(--color-success); }
.tl-item.is-now  .tl-dot { background: var(--color-primary); }
.tl-item::before { content: ""; position: absolute; left: 12px; top: 28px; bottom: -2px; width: 2px; background: var(--color-line); }
.tl-item:last-child::before { display: none; }
.tl-item.is-done::before { background: var(--color-success); }
.tl-item .tl-body { flex: 1; min-width: 0; padding-top: 2px; }
.tl-item .tl-body b { font-family: var(--font-display, 'Mitr', sans-serif); font-weight: 600; font-size: var(--font-md, 14px); display: block; line-height: 1.35; color: var(--color-text); }
.tl-item.is-pending .tl-body b { color: var(--color-muted); }
.tl-item .tl-body span { font-size: var(--font-sm, 13px); color: var(--color-text-soft); }
/* boxed page — จัดเนื้อหากึ่งกลาง จำกัดความกว้าง (เลือกใช้ด้วย <main class="page boxed">) */
.page.boxed { max-width: 1430px; margin-inline: auto; }
