/* One Platform — the design system applied to Purchasing Webapp (2026-10-05).
   Loads LAST: style.css → shell.css → prq-phone.css → tokens.css → this file.
   Source of truth: the live design system's tokens.json + README + porting.md
   (https://claude.ai/artifact/M6RQSrQE3QbRD4xMJay59c). Colour values never appear here or in
   style.css as literals: everything is a token, so a dark theme is a matter of [data-theme="dark"]
   on <html> (not switched on yet — bell.css still carries its own literal palette).
   Fleet references for the same port: yoguruto-claim-webapp (tokens.css + harbor.css) and
   yoku-one (DESIGN.md). */

/* ── Legacy variable aliases ──────────────────────────────────────────────────────────────
   style.css's own :root names re-pointed at the tokens; every rule that still says var(--primary)
   etc. re-themes from here. --border/--danger/--success/--warning share their names with tokens.css,
   which loads later and wins (the Last-Wins Rule), so they are not repeated. */
:root {
  --primary: var(--brand-600);       /* a FILL: blue text is --brand-text (the Blue Text Rule) */
  --primary-dark: var(--brand-700);
  --primary-light: var(--brand-100);
  --bg: var(--surface-page);
  --card: var(--surface);
  --text: var(--ink);
  --muted: var(--ink-muted);
  --danger-bg: var(--danger-surface);
  --warning-bg: var(--warning-surface);
  --radius: var(--radius-lg);
  --hdr-h: 4.5rem;                   /* desktop top bar: 72px (size-topbar), room for the 48px roundel */
}

/* ── Type: one family, hierarchy by weight (porting.md §2) ─────────────────────────────── */
/* The fleet's +2pt Root Rule (YOKU ONE DESIGN.md; YOKU CS tokens.css): the same reading size as the sibling
   apps. Every font size here is rem-based, so this one line scales the app; style.css pins body to a literal
   16px, hence the body line. */
html { font-size: calc(16px + 2pt); }
body {
  font-size: 1rem;
  font-family: var(--font-sans);
  background: var(--surface-page);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 { color: var(--ink); }
.page-header h1 { font-weight: 700; }
/* section and card titles: 600, and ink — a title that opens nothing is never blue */
.section-title, .card-title, .board-col-header .name { font-weight: 600; color: var(--ink); }
.page-content > .section-title { font-size: 1.05rem; }
/* tabular figures wherever numbers line up */
td, .kpi-tile .v, .my-tile-n, .tab-count, .nav-badge, .score-pill { font-variant-numeric: tabular-nums; }

/* ── Header & sidebar: the fleet shell, static/shell.css. Only the signed-out page header (login) is left
   here: its Yoku Group roundel on the blue band, at the logo's 48px minimum. ── */
.page-header .subtitle { opacity: 0.88; }
.header-logo { width: 48px; height: 48px; padding: 0; background: none; border-radius: 0; object-fit: contain; }

/* ── Cards on a tinted page ─────────────────────────────────────────────────────────────── */
.card { border-radius: var(--radius-lg); border: 1px solid var(--border); box-shadow: var(--shadow-card); }   /* YOKU ONE's card */
/* a card nested in a card takes a border, never a second shadow (the Two-Level Rule) */
.card .card { box-shadow: none; border: 1px solid var(--border); }
/* The bell list clips its rows (overflow: hidden) and each row is one stretched link: at radius-lg the
   last row's corner fell outside the card and a tap there missed (scripts/bell_check.py, 360px). */
.bell-page .notif-card { border-radius: var(--radius-md); }

/* ── Buttons: one blue per screen, everything else outline ─────────────────────────────── */
.btn { border-radius: var(--radius-xl); font-weight: 600; min-height: var(--size-tap);
  transition: background-color .12s ease, border-color .12s ease, color .12s ease; }
.btn:active { transform: none; }               /* colour-only motion */
.btn:disabled, .btn[disabled] { opacity: 0.45; box-shadow: none; }
.btn-sm { min-height: 36px; border-radius: var(--radius-md); }
.btn-primary { background: var(--brand-600); color: var(--on-brand); box-shadow: var(--shadow-raised); }
.btn-primary:hover { background: var(--brand-700); }
.btn-outline { background: var(--surface); color: var(--brand-text); border: 1.5px solid var(--border-strong); }
.btn-outline:hover { background: var(--brand-050); }
/* success-solid is the Approve button and nothing else (README: "the only solid green in the product");
   the approve buttons keep it through .apr-act__btn--approve. Every other .btn-success — รับงานนี้, ปิดเคส,
   รับของแล้ว — is the page's next action, so it is the one blue. */
.btn-success { background: var(--brand-600); color: var(--on-brand); box-shadow: var(--shadow-raised); }
.btn-success:hover { background: var(--brand-700); }
.btn-danger { background: var(--danger-solid); color: var(--on-danger); }
.btn-danger:hover { background: var(--danger-solid); filter: brightness(0.9); }
.btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* ── Fields: control edge 1.5px, radius-md, ONE focus ring (porting.md §4) ─────────────────
   Inputs are selected by exclusion so a type added later is covered too. */
.page-content :is(input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="file"]):not([type="color"]):not([type="range"]), select, textarea) {
  border: 1.5px solid var(--border-strong);
  border-radius: var(--radius-md);
  background-color: var(--surface);
  color: var(--ink);
}
.page-content :is(input, select, textarea)::placeholder { color: var(--ink-subtle); }
.page-content :is(input, select, textarea):focus { border-color: var(--border-strong); box-shadow: none; }
.page-content :is(input, select, textarea):focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.page-content :is(input, select, textarea):disabled { background-color: var(--surface-sunken); border-color: var(--border); }
.field label { color: var(--ink); font-weight: 600; }
/* Prompt is wider than the system face it replaced: a <select> with long option text grew past its flex row
   on a phone (/case/{id}, 2026-10-05). A field may shrink; the control then fills what it is given. */
.field { min-width: 0; }
.page-content select { max-width: 100%; }
input[type="checkbox"], input[type="radio"] { accent-color: var(--brand-600); }
.page-content input[type="file"]::file-selector-button { border: 1.5px solid var(--border-strong); border-radius: var(--radius-xl);
  background: var(--surface); color: var(--brand-text); font: inherit; font-weight: 600; padding: 0.35rem 0.9rem;
  margin-right: 0.6rem; cursor: pointer; transition: background-color .12s ease; }
.page-content input[type="file"]::file-selector-button:hover { background: var(--brand-050); }

/* ── Tables: sunken header band, hairline rows, hover that means nothing ───────────────── */
.wl-table th, .items-table th { background: var(--surface-sunken); color: var(--ink); font-weight: 600; }
.wl-table tbody tr:hover > td { background-color: var(--surface-hover); }

/* The table IS the card (DataTable README; YOKU ONE admin.css, 2026-10-05): a card holding a table
   drops its padding and shadow and becomes the frame — the header band and row lines run edge to
   edge, clipped to its corners; the outer columns carry the card's inset instead; anything else in
   that card (a title, a footnote, a form row) keeps the inset. Every table was 23px inside a padded,
   shadowed card. A nested items list inside a cell is not a data table and is left alone. */
.card:has(> .wl-table, > .wl-table-wrap) { padding: 0; box-shadow: none; }
.card:has(> .wl-table, > .wl-table-wrap):not(.wl-table-wrap) { overflow: hidden; }
.card:has(> .wl-table, > .wl-table-wrap) > :not(.wl-table, .wl-table-wrap, script, style, input[type="hidden"]) {
  margin: var(--space-4) var(--space-5);
}
.card > .wl-table-wrap { border: 0; border-radius: 0; box-shadow: none; }
/* A table deeper inside a card (a table field of an Approval form, a case's item list) brings its own
   frame instead, so its header band still sits inside a border and never floats on the card. */
.wl-table-wrap:not(.card, .card > *), .items-wrap { border: 1px solid var(--border); border-radius: var(--radius-md); }
/* Wide tables keep wrapping header labels (2026-09-27): with nowrap the Approval list's assign column
   leaves the screen at 1366px. The one exception to the DataTable's nowrap header. */
:is(.card > .wl-table, .card > .wl-table-wrap > .wl-table) > * > tr > :first-child { padding-left: var(--space-5); }
:is(.card > .wl-table, .card > .wl-table-wrap > .wl-table) > * > tr > :last-child { padding-right: var(--space-5); }
.wl-table th { padding-block: 0.7rem; }
/* Cells centre vertically, except tables whose rows carry stacked controls or an opening item list:
   those align to the top, so the row's text sits level with its first control. */
.wl-table td { vertical-align: middle; }
:is(.appr-table, .tb-table, .wl-table:has(details, .apr-act)) td { vertical-align: top; }
/* Say when there is more to the side: a soft edge shadow only while columns remain to scroll to
   (background-attachment: local masks over pinned shadows; pure CSS). */
.wl-table-wrap {
  background:
    linear-gradient(to right, var(--surface) 30%, transparent) left,
    linear-gradient(to left, var(--surface) 30%, transparent) right,
    radial-gradient(farthest-side at 0 50%, color-mix(in srgb, var(--ink) 18%, transparent), transparent) left,
    radial-gradient(farthest-side at 100% 50%, color-mix(in srgb, var(--ink) 18%, transparent), transparent) right;
  background-repeat: no-repeat;
  background-color: var(--surface);
  background-size: 24px 100%, 24px 100%, 10px 100%, 10px 100%;
  background-attachment: local, local, scroll, scroll;
}

/* ── Alerts → InfoNote ──────────────────────────────────────────────────────────────────── */
.alert { border-radius: var(--radius-md); }
.alert-success { background: var(--success-surface); color: var(--success); }

/* ── Status badges: a word on its tint, with a bright dot (the Bright Dot + Pill Contrast Rules) ── */
.badge { font-weight: 600; border-radius: var(--radius-pill); line-height: 1.5; }
:is(.badge-triage, .badge-age-warn, .badge-lk-pending, .badge-wk-new, .badge-wk-waiting_info, .badge-await, .apr-warn, .badge-pl-warn, .badge-plan,
    .badge-ready, .badge-ok, .badge-lk-approved, .badge-wk-done, .apr-ok, .badge-due-ok,
    .badge-cancelled, .badge-age-late, .badge-leave, .badge-lk-rejected, .apr-bad,
    .badge-active, .badge-wk-in_progress, .badge-pl, .badge-wk-hold,
    .badge-wk-received,
    .badge-closed, .badge-lk-deleted, .badge-lk-other, .badge-wk-other, .badge-set_aside, .badge-wk-cancelled, .apr-muted).badge::before {
  content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 6px; border-radius: 50%;
  vertical-align: 0.12em; background: var(--dot, currentColor);
}
:is(.badge-triage, .badge-age-warn, .badge-lk-pending, .badge-wk-new, .badge-wk-waiting_info, .badge-await, .apr-warn, .badge-pl-warn, .badge-plan).badge { --dot: var(--warning-dot); }
:is(.badge-ready, .badge-ok, .badge-lk-approved, .badge-wk-done, .apr-ok, .badge-due-ok).badge { --dot: var(--success-dot); }
:is(.badge-cancelled, .badge-age-late, .badge-leave, .badge-lk-rejected, .apr-bad).badge { --dot: var(--danger-dot); }
:is(.badge-active, .badge-wk-in_progress, .badge-pl, .badge-wk-hold).badge { --dot: var(--info-dot); }
:is(.badge-closed, .badge-lk-deleted, .badge-lk-other, .badge-wk-other, .badge-set_aside, .badge-wk-cancelled, .apr-muted).badge {
  box-shadow: inset 0 0 0 1px var(--border); }

/* ── View-as banner: the one warning surface, no rail ──────────────────────────────────── */
.view-as-bar { border-radius: var(--radius-md); }

/* ── Focus: one 2px ring everywhere interactive ─────────────────────────────────────────── */
a:focus-visible, button:focus-visible, summary:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* A toolbar row whose heading moved into the top bar (2026-10-05) keeps its button on the right. */
.page-toolbar > :only-child, .detail-head > :only-child { margin-left: auto; }

/* One blue per screen (the system's first principle): on the Approval LIST every row carried a filled
   "มอบหมาย + ยืนยัน", so a screen of ten rows had ten primary actions. In a row it is the outline button;
   the detail page keeps the filled one, where it is that page's next action. */
.apr-act[data-where="row"] .apr-act__btn--assign { background: var(--surface); color: var(--brand-text);
  border: 1.5px solid var(--border-strong); box-shadow: none; }
.apr-act[data-where="row"] .apr-act__btn--assign:hover { background: var(--brand-050); }

/* Dark mode: native controls (date pickers, selects, scrollbars) follow the theme. */
[data-theme="dark"] { color-scheme: dark; }
[data-theme="light"] { color-scheme: light; }

/* No tint on tint (the design system README): a status pill on a row or card that is already tinted takes the
   surface as its fill and a full border in its own status colour, or it vanishes into its ground — the "7 วัน"
   pill on a red overdue row did (2026-10-05). The dot and the word stay as they are. */
:is(.wl-row-overdue, .wl-row-due, .wl-row-ready, .apr-row.is-pending, .row-plan, .row-received, .case-card.overdue,
    .lark-open--mine, .kpi-tile--alert, .kpi-tile--warn, .kpi-tile--ok, .pl-card--closed, .alert) .badge {
  background: var(--surface);
  box-shadow: inset 0 0 0 1px currentColor;
}

/* ── A colour per person (2026-10-05, main.who_cls()) ──────────────────────────────────────────
   16 pastels chosen by the user. Light mode: the chip IS the colour, with an edge a step darker so
   the palest ones still read as a chip on white. Dark mode: a pastel fill would put light text on a
   light ground, so the chip is a soft tint of the colour with a border in the colour itself. The name
   is always ink. */
:root { --who-1: #fbf8cc; --who-2: #fde4cf; --who-3: #ffcfd2; --who-4: #f1c0e8; --who-5: #cfbaf0; --who-6: #a3c4f3; --who-7: #90dbf4; --who-8: #8eecf5; --who-9: #98f5e1; --who-10: #b9fbc0; --who-11: #eae4e9; --who-12: #d2d2cf; --who-13: #d6eadf; --who-14: #dfe7fd; --who-15: #e2ece9; --who-16: #e2cfc4; }
:root, [data-theme="light"] { --who-mix: 100%; --who-edge: 18%; }
[data-theme="dark"] { --who-mix: 22%; --who-edge: 0%; }
.who-1 { --w: var(--who-1); } .who-2 { --w: var(--who-2); } .who-3 { --w: var(--who-3); } .who-4 { --w: var(--who-4); } .who-5 { --w: var(--who-5); } .who-6 { --w: var(--who-6); } .who-7 { --w: var(--who-7); } .who-8 { --w: var(--who-8); } .who-9 { --w: var(--who-9); } .who-10 { --w: var(--who-10); } .who-11 { --w: var(--who-11); } .who-12 { --w: var(--who-12); } .who-13 { --w: var(--who-13); } .who-14 { --w: var(--who-14); } .who-15 { --w: var(--who-15); } .who-16 { --w: var(--who-16); }
:is(.chip, .chip-filter, label, .nick-chip).who { background: color-mix(in srgb, var(--w) var(--who-mix), var(--surface));
  border: 1px solid color-mix(in srgb, var(--w), var(--ink) var(--who-edge)); color: var(--ink); }
label.who { border-radius: var(--radius-pill); padding: 2px var(--space-3) 2px var(--space-2); }
label.who:has(input:checked) { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--w), var(--ink) 35%); font-weight: 600; }
.chip-filter.who.is-on { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--w), var(--ink) 35%); font-weight: 600; }
/* A name that heads something (a บอร์ดทีม column, a case's owner) is the same colour chip, larger, so Praew
   tells people apart by colour at a glance (the user, 2026-10-08: dots read too small). */
.chip.chip-lg { font-size: 0.95rem; padding: 3px 12px; margin: 0; }
/* ทีม & ตั้งค่า: the swatch picker */
.who-pick > summary { list-style: none; cursor: pointer; font-size: 0.82rem; color: var(--brand-text); margin-top: var(--space-1); }
.who-pick > summary::-webkit-details-marker { display: none; }
.who-pick__form { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; margin-top: var(--space-2); max-width: 300px; }
.who-pick__sw { position: relative; cursor: pointer; }
.who-pick__sw input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.who-pick__sw span { display: block; width: 26px; height: 26px; border-radius: 50%; background: var(--w); border: 2px solid var(--surface);
  box-shadow: 0 0 0 1px var(--border-strong); }
.who-pick__sw input:checked + span { box-shadow: 0 0 0 2px var(--ink); }
.who-pick__sw input:focus-visible + span { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* ── Reading font and text size, per browser (/me/display, 2026-10-08) ──
   Purchasing reads a lot of text all day: body text may be Segoe UI instead of Prompt (the user,
   2026-10-08; Maitree was tried the same day and dropped). Segoe UI is a Windows system font that cannot
   be shipped with the app, and it has no Thai, so Windows draws Thai in its own Leelawadee UI and other
   devices fall back to their system font. Only the reading text changes. Headings, buttons, form controls, badges and
   chips keep Prompt (matched by name, so a new *-badge / *-chip / *-pill class follows without an edit),
   and so do the sidebar and top bar, which sit outside .page-content. The size scales the root, so every
   rem-sized text grows together and the layout follows it. */
html[data-font="segoe"] .page-content { font-family: "Segoe UI", "Leelawadee UI", "Leelawadee", system-ui, sans-serif; }
html[data-font="segoe"] .page-content :is(h1, h2, h3, h4, h5, h6, legend, .section-title, .card-title, button, .btn,
  input, select, label, th, summary, .nfilter, .notif-when, [class*="badge"], [class*="chip"], [class*="pill"], [class*="btn"]) {
  font-family: var(--font-sans);
}
html[data-text-size="sm"] { font-size: calc((16px + 2pt) * 0.9); }
html[data-text-size="lg"] { font-size: calc((16px + 2pt) * 1.1); }
html[data-text-size="xl"] { font-size: calc((16px + 2pt) * 1.2); }

/* the page itself (templates/display_settings.html) */
.ds-card { max-width: 46rem; display: grid; gap: 1.4rem; }
.ds-group { border: 0; margin: 0; padding: 0; min-width: 0; }
.ds-group > legend { padding: 0; margin-bottom: 0.5rem; }
.ds-hint { margin: 0 0 0.7rem; font-size: 0.88rem; }
.ds-options { display: grid; gap: 0.6rem; }
.ds-options--size { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 480px) { .ds-options--size { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.ds-hint--after { margin: 0.6rem 0 0; }
.ds-opt { display: grid; grid-template-columns: auto 1fr; align-items: center; column-gap: 0.6rem; row-gap: 0.25rem;
  min-height: var(--size-tap); padding: 0.7rem 0.9rem; border: 1.5px solid var(--border); border-radius: var(--radius-md);
  background: var(--surface); cursor: pointer; }
.ds-opt:hover { background: var(--surface-hover); }
.ds-opt:has(input:checked) { border-color: var(--brand-600); background: var(--brand-050); }
.ds-opt input { margin: 0; accent-color: var(--brand-600); }
.ds-opt__name { font-weight: 600; }
.ds-opt__sample { grid-column: 2; font-size: 1.05rem; line-height: 1.6; color: var(--ink); }
.page-content .ds-opt__sample--prompt { font-family: "Prompt", var(--font-sans); }
.page-content .ds-opt__sample--segoe { font-family: "Segoe UI", "Leelawadee UI", "Leelawadee", system-ui, sans-serif; }
.ds-size-sm { font-size: 0.9em; }
.ds-size-lg { font-size: 1.1em; }
.ds-size-xl { font-size: 1.2em; }
.ds-preview { padding: 1rem 1.1rem; border-radius: var(--radius-md); background: var(--surface-sunken); }
.ds-preview p { margin: 0; line-height: 1.75; }
.ds-preview .ds-preview__label { margin-bottom: 0.35rem; font-size: 0.8rem; font-weight: 600; color: var(--ink-muted); }
.ds-saved { margin: 0; min-height: 1.4em; font-size: 0.85rem; }
/* "×3" after a name chip: how many that person entered (รายงาน, per day) */
.chip-n { margin: 0 6px 0 -1px; font-size: 0.78rem; font-weight: 600; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
