/* ============================================================================
   Design tokens — the single source of truth for the whole app.
   ----------------------------------------------------------------------------
   Every colour, space and radius lives here. A rule that hardcodes a hex value
   cannot follow the theme, which is how this file ended up with ~30 colours the
   dark mode had to override one by one.

   The SOFT variants matter most: `.status-success { background: var(--success-soft) }`
   works in both themes from one rule, replacing a dark-mode override per status.
   ========================================================================== */
:root {
  /* Surfaces — the same language as the hand-made payout page the operator
     modelled the look on: a cool light-grey canvas (#f5f5f7) with pure-white
     cards floating on it. Depth comes from one soft wide shadow, not borders. */
  --bg: #f5f5f7;
  --surface: #ffffff;
  --surface-muted: #f2f2f4;
  --surface-sunken: #e9e9ee;
  --hover-bg: #ededf0;

  /* Text and lines */
  --text: #161617;
  --text-soft: #3a3a3c;
  --muted: #65656b;
  --line: #e6e6e9;
  --line-strong: #cfcfd4;

  /* One accent, used only for actions — the payout page's blue, darkened a
     step so white button text passes 4.5:1. Information stays text/muted, so a
     blue thing on screen always means "you can act". */
  --accent: #0067cf;
  --accent-hover: #0056ad;
  --accent-soft: #eef6ff;
  --accent-on-soft: #005ab6;
  --accent-contrast: #ffffff;

  /* Status. Reserved for status only — never for decoration. */
  --success: #18794e;
  --success-soft: #f0f8f3;
  --warning: #8a560a;
  --warning-soft: #f8eddb;
  --danger: #b3453a;
  --danger-soft: #f8e7e4;
  --info: #2f6f8f;
  --info-soft: #e3eef4;

  /* Shape and depth — generous radii and one soft, wide shadow per card. The
     hairline border is nearly invisible; it only keeps cards defined on
     monitors that crush the shadow. */
  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 20px;
  --radius-pill: 999px;
  --card-line: rgba(0, 0, 0, .055);
  --shadow-sm: 0 1px 2px rgba(22, 22, 23, .05);
  --shadow: 0 18px 50px rgba(22, 22, 23, .045);
  --shadow-lg: 0 24px 60px rgba(22, 22, 23, .14);

  /* Spacing scale */
  --space-xs: 4px;
  --space-sm: 8px;
  --space-md: 12px;
  --space-lg: 16px;
  --space-xl: 24px;
  --space-2xl: 32px;

  /* Type. Latin resolves to Inter and Thai falls through to IBM Plex Sans Thai
     -- font fallback is per glyph, so one stack serves both scripts. Before
     this the app loaded no Thai face at all, so every Thai character used
     whatever the OS supplied: a different shape on Windows, iOS and Android,
     and a different x-height from the numbers beside it. */
  --font-ui: 'Inter', 'IBM Plex Sans Thai', system-ui, -apple-system, sans-serif;
  --text-xs: 11px;
  --text-sm: 12px;
  --text-base: 13px;
  --text-md: 15px;
  --text-lg: 18px;
  --text-xl: 24px;

  /* Compatibility aliases. Older rules were written against these names; they
     stay so the whole stylesheet did not have to be renamed at once. */
  --text-primary: var(--text);
  --text-secondary: var(--muted);
  --text-muted: var(--muted);
  --border-light: var(--line);
  --border-color: var(--line);
  --bg-body: var(--bg);
  --background-color: var(--bg);
  --bg-surface: var(--surface);
  --surface-bg: var(--surface);
  --surface-bg-alt: var(--surface-muted);
  --backdrop-bg: rgba(28, 31, 29, .42);
  --brand: var(--accent);
  --primary-color: var(--accent);
  --danger-color: var(--danger);
  --danger-bg: var(--danger-soft);

  font-family: var(--font-ui);
  color: var(--text);
  background: var(--bg);
  font-variant-numeric: tabular-nums;
}

/* Dark theme. Only the values change -- every rule above is written against
   tokens, so nothing needs a [data-theme="dark"] counterpart. */
[data-theme="dark"] {
  --bg: #101012;
  --surface: #1c1c1f;
  --surface-muted: #242428;
  --surface-sunken: #0c0c0e;
  --hover-bg: #2a2a2f;

  --text: #ececf0;
  --text-soft: #c7c7ce;
  --muted: #a3a3ac;
  --line: #2e2e33;
  --line-strong: #46464d;

  --accent: #4da3ff;
  --accent-hover: #6cb3ff;
  --accent-soft: #122a44;
  --accent-on-soft: #7dbcff;
  --accent-contrast: #0b1524;

  --success: #63c993;
  --success-soft: #15291f;
  --warning: #dcae5b;
  --warning-soft: #2e2413;
  --danger: #e4837a;
  --danger-soft: #33201d;
  --info: #6aa9cc;
  --info-soft: #16242d;

  --card-line: rgba(255, 255, 255, .07);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);
  --shadow: 0 18px 50px rgba(0, 0, 0, .38);
  --shadow-lg: 0 24px 60px rgba(0, 0, 0, .55);
  --backdrop-bg: rgba(0, 0, 0, .58);
}

* { box-sizing: border-box; }
html { min-width: 320px; background: var(--bg); }
body { min-height: 100vh; margin: 0; display: flex; background: var(--bg); }
button, input, select, textarea { font: inherit; }
button, a { -webkit-tap-highlight-color: transparent; }
button { cursor: pointer; transition: transform 0.1s ease, background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease; }
button:active { transform: scale(0.98); }
button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
input, select, textarea { color: var(--text); border: 1px solid var(--line); border-radius: 10px; background: var(--surface); min-height: 38px; padding: 7px 12px; }
select { max-width: 190px; }
textarea { min-height: 78px; resize: vertical; }
input::placeholder { color: var(--muted); }

/* Wider than the old 220px because the sidebar now carries the channel list,
   and a truncated channel name is not a name you can navigate by. overflow:
   hidden keeps the scroll inside .sidebar-streamer-list instead of scrolling
   the brand and nav buttons out of reach. */
.sidebar { background: var(--surface); border-right: 1px solid var(--line); flex: 0 0 260px; min-height: 100vh; padding: 20px 12px; display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh; overflow: hidden; }
.brand { display: flex; align-items: center; gap: 10px; padding: 0 8px 25px; border-bottom: 1px solid var(--line); }
.brand-mark { width: 32px; height: 32px; border-radius: 8px; background: var(--accent); color: white; display: grid; place-items: center; font-size: 16px; font-weight: 700;  }
.brand strong, .brand small { display: block; }
.brand strong { font-size: 15px; letter-spacing: .1px; font-weight: 700; letter-spacing: -.2px; }
.brand small { color: var(--muted); font-size: 11px; margin-top: 1px; }
.nav-list { display: grid; gap: 4px; padding-top: 17px; }
.nav-item { border: 0; background: transparent; color: var(--muted); border-radius: 8px; font-size: 14px; font-weight: 500; padding: 10px 12px; text-align: left; display: flex; align-items: center; gap: 10px; }
.nav-item svg { flex-shrink: 0; opacity: 0.7; transition: opacity 0.15s ease; }
.nav-item:hover { background: var(--surface-muted); color: var(--text); }
.nav-item:hover svg { opacity: 1; }
.nav-item.is-active { background: var(--accent); color: var(--accent-contrast); font-weight: 600; }
.nav-item.is-active svg { opacity: 1; stroke: var(--accent-contrast); }

/* Channel list — the permanent spine of the app.
   It gets the leftover height (flex:1) and scrolls on its own, so the three nav
   buttons above and the quiet links below never move no matter how many
   streamers there are. */
.sidebar-streamers { display: flex; flex-direction: column; min-height: 0; flex: 1; margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line); }
.sidebar-streamers-head { display: flex; align-items: baseline; justify-content: space-between; padding: 0 8px 8px; }
.sidebar-streamers-head span:first-child { font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.sidebar-streamers-count { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.sidebar-search { width: 100%; margin-bottom: 8px; padding: 7px 10px; font-size: 13px; font-family: inherit; color: var(--text); background: var(--surface-sunken); border: 1px solid transparent; border-radius: var(--radius-sm); }
.sidebar-search:focus { outline: none; background: var(--surface); border-color: var(--accent); }
.sidebar-streamer-list { list-style: none; margin: 0; padding: 0 0 4px; overflow-y: auto; overscroll-behavior: contain; flex: 1; min-height: 0; }
.sidebar-streamer { width: 100%; border: 0; background: transparent; border-radius: var(--radius-sm); padding: 6px 8px; display: flex; align-items: center; gap: 8px; text-align: left; cursor: pointer; }
.sidebar-streamer:hover { background: var(--surface-muted); }
.sidebar-streamer.is-current { background: var(--accent-soft); }
.sidebar-streamer.is-dim { opacity: .45; }
.sidebar-streamer-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; background: var(--line-strong); }
.sidebar-streamer-dot[data-status="active"] { background: var(--success); }
.sidebar-streamer-dot[data-status="paused"] { background: var(--warning); }
.sidebar-streamer-name { min-width: 0; flex: 1; }
.sidebar-streamer-name strong { display: block; font-size: 13px; font-weight: 500; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar-streamer-name small { display: block; font-size: 11px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar-streamer-flag { flex-shrink: 0; font-size: 11px; font-weight: 700; line-height: 1; padding: 3px 5px; border-radius: 5px; color: var(--warning); background: var(--warning-soft); }
.sidebar-streamer-empty { padding: 10px 8px; font-size: 12px; color: var(--muted); }
.sidebar-secondary { display: grid; gap: 2px; padding-top: 10px; border-top: 1px solid var(--line); }
.nav-item-quiet { font-size: 12.5px; font-weight: 400; padding: 7px 12px; }

.workspace { min-width: 0; width: 100%; min-height: 100vh; padding: 0 28px 28px; }
.topbar { min-height: 64px; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--line); }
.kicker { color: var(--accent); font-size: 10px; font-weight: 700; letter-spacing: 1.2px; margin: 0 0 2px; }
.topbar h1 { font-size: 19px; line-height: 1.25; margin: 0; font-weight: 700; }
.topbar-note { color: var(--muted); font-size: 12px; margin: 0; }
.topbar-actions { align-items: center; display: flex; gap: 12px; }
.topbar-close { color: var(--muted); font-size: 12px; min-height: 32px; }
.topbar-close:hover { color: var(--danger); border-color: var(--danger); background: var(--danger-bg); }
.topbar-note::before { content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 6px; background: var(--warning); vertical-align: 1px; }
.topbar-note.is-ready::before { background: var(--success); }

.page { display: none; padding-top: 24px; }
.page.is-active { display: block; }
.page-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; margin-bottom: 17px; }
.page-heading h2, .panel-title h3, .surface h3 { margin: 0; font-size: 17px; line-height: 1.35; }
.page-heading p, .panel-title p { color: var(--muted); font-size: 12px; margin: 4px 0 0; }
.compact-heading { margin-bottom: 13px; }

.button { align-items: center; border: 1px solid transparent; border-radius: 10px; display: inline-flex; justify-content: center; min-height: 36px; padding: 7px 11px; text-decoration: none; white-space: nowrap; font-size: 13px; font-weight: 600; }
.button-primary { background: var(--accent); color: var(--accent-contrast); }
.button-primary:hover { background: var(--accent-hover); }
.button-secondary { background: var(--surface); border-color: var(--line); color: var(--text); }
.button-secondary:hover { background: var(--surface-muted); border-color: var(--line-strong); }
.button-danger { color: var(--danger); }
.icon-button { background: transparent; border: 0; color: var(--muted); min-height: 34px; padding: 6px 7px; border-radius: 6px; font-size: 12px; }
.icon-button:hover { color: var(--text); background: var(--surface-muted); }

/* Cards float on the grey canvas: hairline border + one soft wide shadow,
   exactly like the payout page. Borders no longer draw the eye. */
.surface, .table-surface { background: var(--surface); border: 1px solid var(--card-line); border-radius: var(--radius-lg); box-shadow: var(--shadow); }
.metrics { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 18px; }
.metric { min-height: 108px; border: 1px solid var(--card-line); border-radius: var(--radius-lg); padding: 16px 18px; background: var(--surface); box-shadow: var(--shadow); }
.metric-label { color: var(--muted); font-size: 12px; line-height: 1.4; }
/* The number is the point of the card — let it read from across the room. */
.metric-value { color: var(--text); font-size: 30px; font-weight: 700; line-height: 1.15; margin-top: 8px; letter-spacing: -.02em; }
.metric-value.money { font-size: 24px; }
.metric-note { color: var(--muted); font-size: 11px; margin-top: 4px; }
.split-panels { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; }
.action-panel { min-height: 230px; padding: 20px 22px; }
.panel-title { padding-bottom: 12px; border-bottom: 1px solid var(--line); margin-bottom: 4px; }
.action-list { margin: 0; padding: 0; list-style: none; }
.action-row, .breakdown-row { min-height: 45px; display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 13px; }
.action-row:last-child, .breakdown-row:last-child { border-bottom: 0; }
.action-row small, .breakdown-row small { color: var(--muted); display: block; font-size: 11px; margin-top: 2px; }
.action-link { color: var(--accent); background: transparent; border: 0; font-size: 12px; padding: 4px 0; white-space: nowrap; }

.toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; margin: 0 0 10px; }
.toolbar .search-input { flex: 1 1 230px; max-width: 410px; }
.toolbar .button-secondary { margin-left: auto; }
.toolbar .button-secondary + .button-secondary { margin-left: 0; }
.report-toolbar { margin-bottom: 16px; }
.report-toolbar .endpoint-note { color: var(--muted); margin: 0; font-size: 12px; }
.active-filters { display: flex; flex-wrap: wrap; gap: 6px; min-height: 0; margin: -2px 0 10px; }
.filter-chip { display: inline-flex; align-items: center; gap: 5px; color: var(--text-soft); background: var(--surface-muted); border: 1px solid var(--line); border-radius: 99px; padding: 3px 8px; font-size: 11px; }
.filter-chip button { border: 0; background: transparent; color: inherit; line-height: 1; padding: 0 0 0 2px; }

.table-surface { overflow: hidden; }
.table-scroll { overflow: auto; max-height: calc(100vh - 220px); }
/* A wide table scrolls inside its own box. overflow-x:auto only existed inside
   the narrow-screen media query, so on a desktop an extra column pushed the
   WHOLE PAGE sideways instead of the table. The ≤720px card view overrides this
   back to visible, which is correct -- cards need no scroller. */
.data-table-container { overflow-x: auto; }
/* No minimum width. `max(100%, 780px)` forced EVERY table in the app to be at
   least 780px wide, which is why every one of them scrolled sideways even when
   it had four short columns. Width now comes from the content, and the
   container scrolls only when the content genuinely needs it. */
table { border-collapse: separate; border-spacing: 0; width: 100%; font-size: var(--text-base); }
th, td { background: var(--surface); border-bottom: 1px solid var(--line); text-align: left; vertical-align: middle; white-space: nowrap; }
th { color: var(--muted); font-size: 11px; font-weight: 700; height: 42px; padding: 8px 12px; position: sticky; top: 0; z-index: 2; }
td { height: 50px; padding: 10px 12px; }
/* หมายเหตุยอดที่ต้องตรวจ: who / what / how, plus the one button that jumps to
   the person -- the fix always lives in their workspace, not in this list. */
.issue-list { display: grid; gap: 8px; }
.issue-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; background: var(--warning-soft); border-radius: 8px; padding: 10px 12px; }
.issue-row > div { display: grid; gap: 2px; min-width: 0; }
.issue-row strong { font-size: 13.5px; }
.issue-row small { color: var(--text-soft); font-size: 12px; }
.issue-how { color: var(--muted); }
.issue-fix { flex-shrink: 0; }
/* หลายคูปองในเซลล์เดียว: แต่ละโค้ดเป็นชิปของตัวเอง */
.value-chip { display: inline-block; padding: 2px 8px; border-radius: 6px; background: var(--surface-sunken); font-size: 12px; font-variant-numeric: tabular-nums; }

/* ป้ายสีธนาคารในตารางรอบจ่าย — สีตราของแต่ละธนาคารเป็นค่าคงที่ของแบรนด์
   จึงเป็นเลขสีตรง ๆ ไม่ใช่ token ธีม (เหมือนกันทั้งโหมดสว่าง/มืด) */
.bank-pill { display: inline-flex; min-height: 24px; align-items: center; padding: 3px 9px; border-radius: 999px; color: #fff; font-size: 11px; font-weight: 700; white-space: nowrap; }
.bank-kbank { background: #138f2d; }
.bank-scb { background: #4e2e7f; }
.bank-ktb { background: #00a6e6; color: #042f44; }
.bank-krungsri { background: #ffd400; color: #3d3300; }
.bank-bbl { background: #1e4598; }
.bank-ttb { background: linear-gradient(110deg, #0066b3 0 62%, #f58220 62% 100%); }
.bank-default { background: var(--muted); }
.copy-account { border: 0; border-radius: 6px; padding: 4px 8px; margin-left: 4px; font-size: 11px; font-weight: 600; color: var(--accent); background: var(--accent-soft); cursor: pointer; }
.copy-account:hover { background: var(--accent); color: var(--accent-contrast); }

/* ── หน้ารอบจ่าย: hero + workspace เหมือนหน้า payout ที่ทำมือ ────────────── */
.payout-hero { display: flex; align-items: center; justify-content: space-between; gap: 48px; padding: 40px 46px; margin-bottom: 18px; min-height: 200px; }
.payout-total > span { color: var(--muted); font-size: 14px; }
.payout-total > strong { display: block; margin: 6px 0; color: var(--accent); font-size: clamp(48px, 5.5vw, 72px); line-height: 1; letter-spacing: -.05em; font-weight: 700; }
.payout-total > small { color: var(--muted); font-size: 13px; }
.payout-progress { width: min(520px, 46%); display: grid; grid-template-columns: repeat(3, 1fr); }
.payout-progress > div { min-height: 82px; padding: 9px 24px; border-left: 1px solid var(--line); display: flex; flex-direction: column; justify-content: center; }
.payout-progress span { color: var(--muted); font-size: 12px; }
.payout-progress strong { margin-top: 7px; font-size: 22px; letter-spacing: -.01em; }
.payout-workspace { padding: 30px 34px 22px; }
.workspace-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 24px; margin-bottom: 18px; }
.workspace-head h2 { margin: 0; font-size: 26px; letter-spacing: -.03em; }
.workspace-head p { margin: 6px 0 0; color: var(--muted); font-size: 13px; }
.pending-pill { flex-shrink: 0; display: inline-flex; align-items: center; padding: 9px 13px; border: 1px solid var(--line); border-radius: var(--radius-pill); background: var(--surface); color: var(--text-soft); font-size: 13px; white-space: nowrap; }
.pending-pill i { display: inline-block; width: 7px; height: 7px; margin-right: 7px; border-radius: 50%; background: var(--warning); }
.pending-pill.is-done i { background: var(--success); }
.report-breakdowns { margin: 18px 0 4px; max-width: 420px; }
.report-breakdowns h3 { font-size: 14px; margin: 0 0 8px; }
@media (max-width: 1000px) {
  .payout-hero { flex-direction: column; align-items: flex-start; gap: 22px; padding: 28px 24px; }
  .payout-progress { width: 100%; }
  .payout-progress > div:first-child { border-left: 0; padding-left: 0; }
}
/* On a phone the three columns were ~95px wide once padding was taken out, so a
   figure like ฿3,750.81 at 22px ran past the edge of its box. Below 700px they
   become rows instead: label on the left, number on the right, which fits any
   amount and reads faster than three cramped stacks. */
@media (max-width: 700px) {
  .payout-progress { grid-template-columns: minmax(0, 1fr); }
  .payout-progress > div { min-height: 0; padding: 11px 0; border-left: 0; border-top: 1px solid var(--line);
    flex-direction: row; align-items: baseline; justify-content: space-between; gap: 14px; }
  .payout-progress > div:first-child { border-top: 0; padding-top: 4px; }
  .payout-progress strong { margin-top: 0; font-size: 19px; white-space: nowrap; }
  .payout-total > strong { overflow-wrap: anywhere; }
  .payout-workspace { padding: 24px 18px 16px; }
  .workspace-head { flex-direction: column; align-items: flex-start; }
}

/* ── หน้า "วันนี้": รายการงานที่แถวคือคน ────────────────────────────────── */
.task-filter { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.task-filter:empty { display: none; }
.task-chip { border: 1px solid var(--line); background: var(--surface); color: var(--text-soft); border-radius: var(--radius-pill); padding: 6px 12px; font-size: 12.5px; }
.task-chip b { font-variant-numeric: tabular-nums; }
.task-chip:hover { border-color: var(--line-strong); }
.task-chip.is-active { background: var(--text); border-color: var(--text); color: var(--surface); }
.task-chip-danger { color: var(--danger); border-color: var(--danger-soft); background: var(--danger-soft); }
.task-chip-warning { color: var(--warning); border-color: var(--warning-soft); background: var(--warning-soft); }
.task-chip-info { color: var(--info); border-color: var(--info-soft); background: var(--info-soft); }
.task-chip-danger.is-active, .task-chip-warning.is-active, .task-chip-info.is-active { background: var(--text); border-color: var(--text); color: var(--surface); }

.task-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
/* The left stripe carries the urgency, so scanning down the list reads as a
   priority order without anyone having to read the labels. */
.task-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 14px 16px; border: 1px solid var(--card-line); border-left: 3px solid var(--line-strong); border-radius: var(--radius); background: var(--surface-muted); }
.task-row-danger { border-left-color: var(--danger); }
.task-row-warning { border-left-color: var(--warning); }
.task-row-info { border-left-color: var(--info); }
.task-body { min-width: 0; }
.task-body > strong { display: block; font-size: 14.5px; margin-bottom: 5px; }
.task-reasons { display: flex; flex-wrap: wrap; align-items: center; gap: 5px 8px; }
.task-reasons small { color: var(--text-soft); font-size: 12px; margin-right: 6px; }
.task-tag { font-size: 11px; font-weight: 600; padding: 2px 7px; border-radius: var(--radius-sm); }
.task-tag-danger { color: var(--danger); background: var(--danger-soft); }
.task-tag-warning { color: var(--warning); background: var(--warning-soft); }
.task-tag-info { color: var(--info); background: var(--info-soft); }
.task-go { flex-shrink: 0; }

/* ── Top 5: อันดับผลงาน แท่งเทียบกับที่หนึ่ง ─────────────────────────────── */
.top-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; counter-reset: rank; }
.top-row { display: flex; align-items: center; gap: 14px; padding: 12px 14px; border-radius: var(--radius); cursor: pointer; }
.top-row:hover { background: var(--surface-muted); }
.top-rank { flex-shrink: 0; width: 34px; height: 34px; display: grid; place-items: center; border-radius: var(--radius-pill); font-size: 16px; font-weight: 700; background: var(--surface-sunken); color: var(--muted); }
.top-rank-1, .top-rank-2, .top-rank-3 { background: transparent; font-size: 22px; }
.top-rank-4, .top-rank-5 { font-size: 13px; }
.top-body { flex: 1; min-width: 0; display: grid; gap: 5px; }
.top-name { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.top-name strong { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.top-name small { color: var(--muted); font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.top-bar { height: 8px; border-radius: var(--radius-pill); background: var(--surface-sunken); overflow: hidden; }
.top-bar > i { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--accent), var(--info)); }
.top-detail { color: var(--muted); font-size: 11.5px; }
.top-row:first-child .top-bar > i { background: linear-gradient(90deg, var(--success), var(--accent)); }

/* ── หน้าสตรีมเมอร์: การ์ดรายคน + ไทล์ตัวกรอง ──────────────────────────── */
.roster-hero { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 18px; }
.roster-tile { display: grid; gap: 2px; text-align: left; padding: 18px 20px; border: 1px solid var(--card-line); border-radius: var(--radius-lg); background: var(--surface); box-shadow: var(--shadow); }
.roster-tile span { color: var(--muted); font-size: 12px; }
.roster-tile strong { font-size: 30px; line-height: 1.1; letter-spacing: -.02em; }
/* A baht figure is longer than a count, so it gets its own size rather than
   wrapping or overflowing the tile. */
.roster-tile strong.is-money { font-size: 23px; }
.roster-tile small { color: var(--muted); font-size: 11px; }
.roster-tile:hover { border-color: var(--line-strong); }
.roster-tile.is-active { outline: 2px solid var(--accent); outline-offset: -2px; }
.roster-tile-warning strong { color: var(--warning); }

.view-switch { flex-shrink: 0; display: inline-flex; padding: 2px; gap: 2px; background: var(--surface-sunken); border-radius: var(--radius); }
.view-option { border: 0; background: transparent; color: var(--muted); border-radius: var(--radius-sm); padding: 6px 14px; font-size: 12.5px; font-weight: 600; }
.view-option.is-active { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }

.streamer-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
/* An explicit display beats the browser's own [hidden] rule, so switching to
   the table view left the cards on screen and the page showed BOTH. */
.streamer-cards[hidden] { display: none; }
.streamer-card { display: grid; gap: 12px; padding: 16px 18px; border: 1px solid var(--card-line); border-radius: var(--radius-lg); background: var(--surface-muted); cursor: pointer; }
.streamer-card:hover { background: var(--surface); box-shadow: var(--shadow); }
.streamer-card-head { display: flex; align-items: center; gap: 10px; }
.streamer-card-head > div { min-width: 0; flex: 1; }
.streamer-card-head strong { display: block; font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.streamer-card-head small { display: block; color: var(--muted); font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.streamer-avatar { flex-shrink: 0; width: 36px; height: 36px; border-radius: var(--radius); display: grid; place-items: center; font-size: 15px; font-weight: 700; color: var(--muted); background: var(--surface-sunken); }
.streamer-avatar[data-status="active"] { color: var(--success); background: var(--success-soft); }
.streamer-avatar[data-status="paused"] { color: var(--warning); background: var(--warning-soft); }
.streamer-card-facts { display: grid; gap: 6px; margin: 0; }
.streamer-card-facts > div { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.streamer-card-facts dt { color: var(--muted); font-size: 11.5px; }
.streamer-card-facts dd { margin: 0; font-size: 12.5px; font-weight: 600; text-align: right; }
.tone-success { color: var(--success); }
.tone-warning { color: var(--warning); }
.tone-danger { color: var(--danger); }
.tone-info { color: var(--info); }
.tone-muted { color: var(--muted); }
.streamer-card-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; border-top: 1px solid var(--line); padding-top: 9px; color: var(--muted); font-size: 11px; }
.streamer-card-foot > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.card-missing { flex-shrink: 0; color: var(--warning); background: var(--warning-soft); border-radius: var(--radius-sm); padding: 2px 6px; font-weight: 600; }

/* Sparkline row: the line stretches, the numbers sit beside it. */
.fact-content { align-items: center !important; }
.fact-content dd { display: flex; align-items: center; gap: 8px; }
.spark { flex-shrink: 0; height: 24px; width: 60px; color: var(--info); }
.spark-up { color: var(--success); }
.spark-down { color: var(--danger); }
.spark-figures { display: grid; line-height: 1.25; text-align: right; }
.spark-figures b { font-size: 12.5px; font-weight: 700; }
.spark-figures i { font-style: normal; font-size: 10.5px; font-weight: 500; }

@media (max-width: 900px) {
  .roster-hero { grid-template-columns: 1fr 1fr; }
  .task-row { flex-direction: column; align-items: flex-start; gap: 10px; }
  .task-go { align-self: stretch; }
}
@media (max-width: 480px) {
  .roster-hero { grid-template-columns: 1fr; }
  .streamer-cards { grid-template-columns: 1fr; }
}

/* ── ฟอร์มเพิ่มลิงก์คอนเทนต์ทีละหลายอัน ──────────────────────────────────── */
.link-rows { display: grid; gap: 6px; margin-bottom: 8px; }
.link-row { display: flex; gap: 6px; align-items: center; }
.link-row input { flex: 1; min-width: 0; }
.link-row-remove { flex-shrink: 0; width: 34px; height: 34px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); color: var(--muted); font-size: 13px; line-height: 1; }
.link-row-remove:hover { border-color: var(--danger); color: var(--danger); background: var(--danger-soft); }
.link-row-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 10px; }
.link-hint { color: var(--muted); font-size: 11.5px; flex: 1; min-width: 200px; }
.link-bulk-note { margin: 0 0 10px; padding: 8px 10px; border-radius: var(--radius-sm); background: var(--info-soft); color: var(--info); font-size: 12px; }
.link-progress { margin-bottom: 10px; padding: 8px 10px; border-radius: var(--radius-sm); background: var(--surface-sunken); color: var(--text-soft); font-size: 12px; overflow-wrap: anywhere; }
.link-progress[hidden], .link-bulk-note[hidden] { display: none; }

/* ── นาฬิกากรุงเทพใน topbar ─────────────────────────────────────────────── */
.topbar-clock { text-align: right; margin-left: auto; margin-right: 14px; line-height: 1.25; }
.topbar-clock strong { display: block; font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: .01em; }
.topbar-clock span { color: var(--muted); font-size: 11px; }
@media (max-width: 560px) { .topbar-clock span { display: none; } }

/* Only rows that really open something invite a click. The channel-name cell
   inside them is a copy zone: it selects like plain text and never opens. */
tbody tr[data-open-streamer], tbody tr[data-open-payment], tbody tr[data-open-contract] { cursor: pointer; }
[data-copy-zone] { cursor: text; user-select: text; }
tbody tr:hover td { background: var(--hover-bg); }
tbody tr:last-child td { border-bottom: 0; }
.sticky-cell { position: sticky; left: 0; z-index: 1; box-shadow: 1px 0 0 var(--line); }
th.sticky-cell { z-index: 3; }
.row-primary { font-weight: 600; color: var(--text); }
.row-subtext { color: var(--muted); font-size: 11px; display: block; overflow: hidden; text-overflow: ellipsis; max-width: 210px; }
.cell-button { display: block; text-align: left; border: 0; color: inherit; background: transparent; font: inherit; width: 100%; margin: -8px -12px; padding: 8px 12px; min-height: 43px; }
.cell-button:hover { color: var(--accent); }
.money { font-variant-numeric: tabular-nums; text-align: right; }
.status { border-radius: 99px; display: inline-block; font-size: 11px; line-height: 1.2; padding: 4px 7px; white-space: nowrap; }
.status-success { background: var(--success-soft); color: var(--success); }
.status-warning { background: var(--warning-soft); color: var(--warning); }
.status-danger { background: var(--danger-soft); color: var(--danger); }
.status-muted { background: var(--surface-muted); color: var(--muted); }
.status-select { border: none; border-radius: 99px; font-size: 11px; line-height: 1.2; padding: 4px 20px 4px 7px; white-space: nowrap; cursor: pointer; appearance: none; -webkit-appearance: none; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'><path d='M0 2l4 4 4-4' fill='none' stroke='currentColor' stroke-width='1.3'/></svg>"); background-repeat: no-repeat; background-position: right 7px center; font-family: inherit; }
.status-select:disabled { opacity: 0.6; cursor: wait; }
.status-select-success { background-color: var(--success-soft); color: var(--success); }
.status-select-warning { background-color: var(--warning-soft); color: var(--warning); }
.status-select-danger { background-color: var(--danger-soft); color: var(--danger); }
.status-select-muted { background-color: var(--surface-muted); color: var(--muted); }
/* Table cells whose value is derived from a linked contract: they look like text
   until hovered, then reveal they are a way into the record that owns the value. */
.cell-link { background: none; border: 0; padding: 2px 4px; margin: -2px -4px; border-radius: 5px; font: inherit; color: inherit; text-align: left; cursor: pointer; display: flex; flex-direction: column; gap: 1px; width: 100%; }
.cell-link:hover, .cell-link:focus-visible { background: var(--surface-muted); }
.cell-link-empty { color: var(--muted); font-size: 12px; border: 1px dashed var(--line); display: inline-block; width: auto; padding: 3px 8px; margin: 0; }
.cell-link-empty:hover { color: var(--text); border-style: solid; }

.warning-row td { background: var(--warning-soft); }
.sensitivity-sensitive { color: var(--danger); }
.sensitivity-internal { color: var(--warning); }

.totals-strip { background: var(--surface-muted); border: 1px solid var(--line); border-radius: 8px; display: flex; flex-wrap: wrap; gap: 0; margin: 0 0 10px; }
.total { min-width: 150px; padding: 9px 13px; border-right: 1px solid var(--line); }
.total:last-child { border-right: 0; }
.total-label { color: var(--muted); display: block; font-size: 11px; }
.total-value { font-size: 14px; font-weight: 700; margin-top: 2px; }

.button-outline { background: transparent; border: 1px solid var(--line-strong); color: var(--text); }
.button-outline:hover { background: var(--surface-muted); border-color: var(--muted); }
.empty-state { color: var(--muted); padding: var(--space-xl) var(--space-lg); text-align: center; font-size: var(--text-base); }
.metric-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-md) var(--space-lg); min-width: 0; }
.metric-card strong { display: block; font-size: var(--text-xl); font-weight: 700; }
.metric-card small { color: var(--muted); font-size: var(--text-sm); }
.section-title { font-size: var(--text-md); font-weight: 600; margin: var(--space-xl) 0 var(--space-sm); }
.text-sm { font-size: var(--text-sm); }
.text-secondary { color: var(--muted); }
.muted-text { color: var(--muted); font-size: var(--text-sm); }
.metrics-grid { display: grid; gap: var(--space-md); grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }

.state { color: var(--muted); padding: 30px 18px; text-align: center; font-size: 13px; }
.state strong { color: var(--text); display: block; font-size: 14px; margin-bottom: 5px; }
.state-error { color: var(--danger); }
.state-loading { color: var(--muted); }
.empty-in-panel { padding: 28px 4px; }
.report-metrics { margin-bottom: 16px; }
.report-breakdowns { margin-bottom: 16px; }
.report-discrepancy { padding: 16px; }
.report-discrepancy h3 { padding-bottom: 11px; border-bottom: 1px solid var(--line); }
.marketing-metrics { margin-bottom: 12px; }
.marketing-note { align-items: flex-start; display: flex; flex-direction: column; gap: 3px; margin-bottom: 13px; padding: 11px 13px; }
.marketing-note strong { font-size: 12px; }
.marketing-note span { color: var(--muted); font-size: 11px; line-height: 1.45; }
.marketing-toolbar { margin-bottom: 10px; }
.segmented { background: var(--surface-muted); border: 1px solid var(--line); border-radius: var(--radius-sm); display: inline-flex; padding: 2px; }
.segment { background: transparent; border: 0; border-radius: 5px; color: var(--muted); font-size: 12px; min-height: 30px; padding: 5px 10px; }
.segment.is-active { background: var(--surface); box-shadow: var(--shadow-sm); color: var(--accent); font-weight: 700; }
.marketing-toolbar .search-input { flex: 1 1 250px; max-width: 430px; }
.marketing-status { white-space: nowrap; }
.marketing-link-select { background: var(--surface); border: 1px solid var(--line-strong); border-radius: 6px; color: var(--text); font: inherit; min-width: 150px; padding: 6px 24px 6px 8px; }
.marketing-link-select:focus { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); outline: none; }

.drawer-backdrop { background: var(--backdrop-bg); inset: 0; position: fixed; z-index: 20; }
.drawer { background: var(--surface); border-left: 1px solid var(--line); box-shadow: var(--shadow); display: flex; flex-direction: column; height: 100vh; max-width: 100vw; position: fixed; right: 0; top: 0; transform: translateX(102%); transition: transform .18s ease-out; width: min(560px, 100vw); z-index: 21; }
.drawer.is-open { transform: translateX(0); }
/* The streamer workspace is a place you work, not a form you fill: contracts,
   payments, deliverables and documents side by side. Contract and payment
   drawers stay at 560px because they really are single forms. */
.drawer.is-wide { width: min(880px, 100vw); }
.drawer-header { align-items: flex-start; border-bottom: 1px solid var(--line); display: flex; justify-content: space-between; min-height: 64px; padding: 14px 16px; }
.drawer-header h2 { font-size: 17px; margin: 0; }
.drawer-body { overflow: auto; padding: 16px; }
.drawer-tabs { border-bottom: 1px solid var(--line); display: flex; gap: 2px; margin: -4px 0 15px; }
.drawer-tab { background: transparent; border: 0; border-bottom: 2px solid transparent; color: var(--muted); font-size: 12px; padding: 9px 10px; }
.drawer-tab.is-active { border-color: var(--accent); color: var(--accent); font-weight: 700; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.form-grid .full { grid-column: 1 / -1; }
.field-label { color: var(--text-soft); display: grid; font-size: 12px; gap: 5px; }
.field-note { color: var(--muted); font-size: 11px; line-height: 1.45; margin: -1px 0 0; }
.form-actions { border-top: 1px solid var(--line); display: flex; justify-content: flex-end; gap: 8px; margin-top: 17px; padding-top: 15px; }
.form-error { background: var(--danger-soft); border-left: 3px solid var(--danger); color: var(--danger); font-size: 12px; margin: 0 0 13px; padding: 9px 10px; }
.detail-list { list-style: none; margin: 0; padding: 0; }
.detail-list li { border-bottom: 1px solid var(--line); padding: 10px 0; font-size: 13px; }
.detail-list li:last-child { border-bottom: 0; }
.detail-list small { color: var(--muted); display: block; font-size: 11px; margin-top: 2px; }
.document-panel { border-bottom: 1px solid var(--line); padding-bottom: 16px; }
.document-row.is-sensitive { background: var(--warning-soft); border-left: 3px solid var(--warning); padding-left: 9px; }
.document-warning { color: var(--warning); font-size: 12px; margin: 7px 0; }
.document-metadata-form { margin-top: 10px; }
.document-metadata-form .form-actions { margin-top: 4px; padding-top: 8px; }
.drawer-section { margin-bottom: 22px; }
.drawer-section h3 { font-size: 14px; margin: 0 0 10px; }
.content-links-panel { color: var(--text); }
.content-links-intro { align-items: center; border-bottom: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: 10px; justify-content: space-between; margin-bottom: 14px; padding-bottom: 10px; }
.content-links-intro > button { flex: 0 0 auto; }
.content-links-intro h3 { margin: 0 0 4px; font-size: 16px; }
.content-links-intro p { color: var(--muted); font-size: 12px; margin: 0; }
.content-link-add, .content-link-form { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; display: grid; gap: 11px; padding: 14px; }
.content-link-add { margin-bottom: 14px; }
.content-link-list { display: grid; gap: 10px; }
.content-link-head { align-items: flex-start; display: flex; gap: 12px; justify-content: space-between; }
.content-link-head strong { display: block; font-size: 14px; line-height: 1.35; }
.content-link-index { color: var(--accent); font-size: 10px; font-weight: 700; letter-spacing: .04em; margin-bottom: 2px; text-transform: uppercase; }
.content-link-head a { color: var(--accent); display: block; font-size: 11px; margin-top: 4px; text-decoration: none; }
.content-link-actions { display: flex; flex: 0 0 auto; gap: 6px; }
.content-link-actions .button { min-height: 28px; padding: 4px 8px; }
.content-link-meta { color: var(--muted); display: flex; flex-wrap: wrap; font-size: 11px; gap: 8px; }
.content-link-meta span { background: var(--surface-muted); border-radius: 999px; padding: 3px 7px; }
.content-link-fields, .content-link-metrics { display: grid; gap: 9px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.content-link-metrics { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.content-link-metrics label { align-items: center; color: var(--muted); display: flex; font-size: 11px; gap: 5px; min-width: 0; white-space: nowrap; }
.content-link-metrics input, .content-link-metrics select { min-height: 30px; padding: 4px 6px; width: 100%; }
.content-link-details { border-top: 1px solid var(--line); padding-top: 9px; }
.content-link-details summary { color: var(--muted); cursor: pointer; font-size: 11px; margin-bottom: 9px; }
.content-link-save { justify-self: start; }
.content-link-empty { border: 1px dashed var(--line); color: var(--muted); font-size: 12px; padding: 22px; text-align: center; }
@media (max-width: 560px) { .content-link-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); } .content-link-head { display: block; } .content-link-actions { margin-top: 8px; } }
/* Two columns left the title box and the date box about 200px each, and a native
   date input needs more than that for "mm/dd/yyyy" plus its calendar button --
   so the date control was cut off. One column below 560px. */
@media (max-width: 560px) {
  .content-link-fields { grid-template-columns: minmax(0, 1fr); }
  .content-link-metrics input, .content-link-metrics select { min-width: 0; }
}
/* Inputs fill their column rather than sitting at their intrinsic width, which
   left a ragged right edge once the fields stacked. */
.content-link-fields label { min-width: 0; }
.content-link-fields input { width: 100%; min-width: 0; }
.warning-box { background: var(--warning-soft); border-left: 3px solid var(--warning); color: var(--warning); font-size: 12px; line-height: 1.5; margin-bottom: 14px; padding: 9px 10px; }

.column-list { border-top: 1px solid var(--line); margin: 10px 0 16px; }
.column-row { align-items: center; border-bottom: 1px solid var(--line); display: grid; gap: 7px; grid-template-columns: minmax(0, 1fr) auto auto auto; min-height: 44px; padding: 6px 0; }
.column-row label { align-items: center; display: flex; gap: 8px; font-size: 13px; min-width: 0; }
.column-row input[type="text"] { min-width: 0; width: 100%; }
.column-row .mini-button { background: transparent; border: 1px solid var(--line); border-radius: 5px; color: var(--text); min-height: 28px; padding: 2px 7px; font-size: 11px; }
.column-row .mini-button:hover { background: var(--surface-muted); }
.column-row .mini-button:disabled { color: var(--muted); cursor: not-allowed; }
.column-heading { color: var(--muted); font-size: 11px; font-weight: 700; margin: 14px 0 4px; }
.column-add { border-top: 1px solid var(--line); padding-top: 15px; }
.column-add h3 { margin: 0 0 10px; font-size: 14px; }
.endpoint-warning { color: var(--warning); font-size: 12px; line-height: 1.45; margin: 10px 0; }
.toast-region { bottom: 18px; display: grid; gap: 8px; max-width: min(360px, calc(100vw - 28px)); position: fixed; right: 18px; z-index: 40; }
.toast { background: var(--text); border-radius: var(--radius-sm); box-shadow: var(--shadow); color: var(--accent-contrast); font-size: 13px; padding: 10px 12px; }
.toast.is-error { background: var(--danger); }
.sr-only { height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; clip: rect(0, 0, 0, 0); white-space: nowrap; }

@media (max-width: 1000px) {
  .workspace { padding-left: 20px; padding-right: 20px; }
  .metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .toolbar .search-input { max-width: none; }
}
@media (max-width: 760px) {
  body { display: block; }
  .sidebar { border-bottom: 1px solid var(--line); border-right: 0; height: auto; min-height: 0; padding: 10px 12px; position: static; width: 100%; overflow: visible; }
  .brand { border-bottom: 0; padding: 0 4px 8px; }
  .nav-list { display: flex; gap: 3px; overflow-x: auto; padding: 0 0 3px; }
  .nav-item { flex: 0 0 auto; font-size: 12px; padding: 7px 9px; }
    /* On a phone the sidebar is a strip across the top, so a scrolling channel
     list would push the actual page below the fold. The streamers page and its
     search box do that job on small screens. */
  .sidebar-streamers { display: none; }
  .sidebar-secondary { display: flex; gap: 3px; border-top: 0; padding-top: 4px; }
  .nav-item-quiet { font-size: 12px; padding: 6px 9px; }
  .workspace { padding: 0 12px 18px; }
  .topbar { min-height: 58px; }
  .page { padding-top: 17px; }
  .page-heading, .split-panels { display: grid; grid-template-columns: 1fr; }
  .page-heading .button { justify-self: start; }
  .metrics { grid-template-columns: 1fr 1fr; }
  .metric { min-height: 88px; }
  .toolbar .button-secondary { margin-left: 0; }
  .table-scroll { max-height: calc(100vh - 250px); }
  .form-grid { grid-template-columns: 1fr; }
  .form-grid .full { grid-column: auto; }
}
@media (max-width: 430px) {
  .metrics { grid-template-columns: 1fr; }
  .page-heading { gap: 10px; }
  .topbar-note { font-size: 11px; }
  .total { border-bottom: 1px solid var(--line); border-right: 0; width: 50%; }
  .total:last-child { border-bottom: 0; }
}

/* Checklist Styles */
.checklist-panel { margin-bottom: var(--space-xl); }
.checklist-form { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-bottom: var(--space-md); }
.checklist-form .search-input { flex: 1; }
.checklist-items { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--space-sm); }
.checklist-item { display: flex; align-items: center; justify-content: space-between; padding: var(--space-sm) var(--space-md); background: var(--bg-surface); border: 1px solid var(--border-light); border-radius: 6px; }
.checklist-item.is-completed .checklist-text { text-decoration: line-through; color: var(--text-muted); }
.checklist-label { display: flex; align-items: center; gap: var(--space-md); cursor: pointer; flex: 1; }
.checklist-checkbox { width: 1.25rem; height: 1.25rem; accent-color: var(--brand); cursor: pointer; }
.checklist-delete { background: none; border: none; color: var(--text-muted); cursor: pointer; padding: var(--space-xs); font-size: 0.875rem; border-radius: 4px; }
.checklist-delete:hover { background: var(--danger-soft); color: var(--danger); }

/* Three buckets side by side on a wide screen, stacked on a narrow one. Each
   keeps its own heading so an empty bucket still says which one it is. */
/* The add-form is input + bucket + button. A flex row of three fixed-ish
   controls is 28px too wide at 375px, which pushed the whole page into a
   sideways scroll, so the text field is allowed to shrink and the row wraps
   onto two lines on a phone. */
.checklist-form .search-input { min-width: 0; }
.checklist-scope-field select { min-height: 38px; width: 100%; }
@media (max-width: 560px) {
  .checklist-form .search-input { flex: 1 1 100%; }
  .checklist-scope-field { flex: 1 1 auto; }
}
.checklist-groups { display: grid; gap: var(--space-lg); grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 900px) { .checklist-groups { grid-template-columns: minmax(0, 1fr); } }
.checklist-group { display: grid; gap: var(--space-sm); min-width: 0; align-content: start; padding: 14px; border: 1px solid var(--card-line); border-radius: var(--radius); background: var(--surface-muted); }
/* A finished column stops asking for attention; an empty one recedes. */
.checklist-group.is-done { background: var(--success-soft); }
.checklist-group.is-done .checklist-group-head h4 { color: var(--success); }
.checklist-group.is-empty { opacity: .72; }
.checklist-bar { height: 4px; border-radius: var(--radius-pill); background: var(--surface-sunken); overflow: hidden; }
.checklist-bar > i { display: block; height: 100%; width: 0; border-radius: inherit; background: var(--accent); transition: width .25s ease; }
.checklist-group.is-done .checklist-bar > i { background: var(--success); }
@media (prefers-reduced-motion: reduce) { .checklist-bar > i { transition: none; } }
.checklist-group-head { align-items: baseline; border-bottom: 1px solid var(--border-light); display: flex; gap: var(--space-sm); justify-content: space-between; padding-bottom: 6px; }
.checklist-group-head h4 { font-size: 13px; margin: 0; }
.checklist-count { color: var(--text-muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.checklist-empty { color: var(--text-muted); font-size: 12px; list-style: none; padding: var(--space-sm) 0; }
.checklist-item .checklist-text { min-width: 0; overflow-wrap: anywhere; }
/* Carried over = not finished when its period ended. Marked, never hidden. */
.checklist-item.is-carryover { border-left: 3px solid var(--warning); }
.checklist-carry { color: var(--warning); display: block; font-size: 11px; margin-top: 2px; }
.checklist-item.is-completed .checklist-carry { color: var(--text-muted); }

/* Duplicate contracts. The panel hides itself when there is nothing to fix, so
   a clean database does not carry a permanent empty warning box. */
.duplicates-panel { border-left: 3px solid var(--warning); margin-bottom: var(--space-xl); }
.dupe-list { display: grid; gap: var(--space-md); list-style: none; margin: 0; padding: 0; }
.dupe-group { border: 1px solid var(--border-light); border-radius: 8px; padding: var(--space-sm) var(--space-md); }
.dupe-head { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; }
.dupe-head small { color: var(--text-muted); font-size: 12px; }
.dupe-copies { display: grid; gap: 6px; list-style: none; margin: 8px 0 0; padding: 0; }
.dupe-copy { align-items: center; background: var(--bg-body); border-radius: 6px; display: flex; gap: 10px; justify-content: space-between; padding: 6px 10px; }
.dupe-copy strong { font-size: 12px; }
.dupe-copy small { color: var(--text-muted); display: block; font-size: 11px; }
.dupe-copy.is-keep { background: color-mix(in srgb, var(--success) 12%, transparent); }
.dupe-flag { background: color-mix(in srgb, var(--warning) 20%, transparent); border-radius: 999px; font-size: 10px; margin-left: 6px; padding: 2px 7px; white-space: nowrap; }
/* "อาจซ้ำ" is a question, not a verdict, so it is outlined rather than filled. */
.dupe-flag.is-maybe { background: transparent; border: 1px dashed var(--border-light); color: var(--text-muted); cursor: help; }

/* Reference figures, folded away by default so the overview stays a to-do list. */
.stats-fold { margin-bottom: var(--space-xl); padding: 0; }
.stats-fold > summary { align-items: baseline; cursor: pointer; display: flex; flex-wrap: wrap; gap: 10px; list-style: none; padding: var(--space-md) var(--space-lg); }
.stats-fold > summary::-webkit-details-marker { display: none; }
.stats-fold > summary::after { content: "▾"; color: var(--text-muted); margin-left: auto; transition: transform .15s ease; }
.stats-fold[open] > summary::after { transform: rotate(180deg); }
.stats-fold > summary span { font-weight: 600; }
.stats-fold > summary small { color: var(--text-muted); font-size: 12px; }
.stats-fold-body { padding: 0 var(--space-lg) var(--space-lg); }
.stats-block { min-width: 0; }
.stats-block .panel-title h3 { font-size: 14px; }
/* An overdue instalment is the one row in the payment panel that cannot wait. */
.action-row.is-late strong { color: var(--danger-color); }

.truncate-url {
  display: inline-block;
  max-width: 200px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}

.detail-list li.clickable-row { cursor: pointer; transition: background 0.15s; padding: 10px 6px; border-radius: 4px; margin: 0 -6px; }
.detail-list li.clickable-row:hover { background: var(--bg); }
.drawer-tab-actions { margin-top: 10px; display: flex; justify-content: flex-end; }
.drawer-tab-actions .button { font-size: 12px; padding: 4px 10px; min-height: 28px; }
.badge { display: inline-block; padding: 2px 6px; border-radius: 4px; font-size: 10px; font-weight: 500; margin-left: 6px; vertical-align: middle; }
.badge-active { background: var(--success-soft); color: var(--success); }
.badge-inactive { background: var(--surface-muted); color: var(--muted); }
.badge-warning { background: var(--warning-soft); color: var(--warning); }

/* Streamer KPI & Marketing Drawer Styles */
.kpi-header-card { background: var(--surface); border: 1px solid var(--card-line); color: var(--text); padding: var(--space-lg); border-radius: var(--radius-lg); margin-bottom: var(--space-lg); box-shadow: var(--shadow); }
.kpi-header-top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.kpi-grade-badge { font-size: 11px; font-weight: 600; padding: 3px 8px; border-radius: 20px; text-transform: uppercase; }
.kpi-grade-High-ROI { background: var(--success); color: var(--accent-contrast); }
.kpi-grade-Profitable { background: var(--info); color: var(--accent-contrast); }
.kpi-grade-Underperforming { background: var(--warning); color: var(--accent-contrast); }
.kpi-grade-No-Data { background: var(--muted); color: var(--accent-contrast); }

.kpi-metrics-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 10px; }
.kpi-metric-item { background: var(--surface-muted); padding: 8px 10px; border-radius: 6px; }
.kpi-metric-label { font-size: var(--text-xs); color: var(--muted); margin-bottom: 2px; }
.kpi-metric-val { font-size: 14px; font-weight: 700; color: var(--text); }

/* Contract expiry traffic-light badges */
.expiry-badge { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 999px; white-space: nowrap; border: 1px solid transparent; }
/* Four steps of the same idea, so they share one shape and differ only in
   which status token they read. Twelve hand-maintained rules (six light, six
   dark) became six that follow the theme on their own. */
.expiry-expired { background: var(--danger-soft); color: var(--danger); border-color: var(--danger); }
.expiry-critical { background: var(--danger-soft); color: var(--danger); }
.expiry-warn { background: var(--warning-soft); color: var(--warning); }
.expiry-ok { background: var(--success-soft); color: var(--success); }
.expiry-none { background: var(--surface-muted); color: var(--muted); }
.expiry-openended { background: var(--info-soft); color: var(--info); }
.checkbox-field { display: flex; align-items: center; gap: 8px; font-weight: 400; }
.checkbox-field input { width: auto; }
.doc-chip { display: inline-block; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; font-size: 12px; color: var(--muted); }

.alias-tag-list { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.alias-tag { background: var(--surface-muted); color: var(--text-soft); font-size: 11px; padding: 3px 8px; border-radius: 4px; display: inline-flex; align-items: center; }
.add-alias-form { display: flex; gap: 6px; margin-bottom: 14px; }
.add-alias-form input { flex: 1; min-height: 32px; font-size: 12px; }
.add-alias-form button { min-height: 32px; font-size: 12px; white-space: nowrap; }


/* Modal */
.modal-backdrop {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background-color: var(--backdrop-bg);
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
}
.modal-backdrop.is-active {
  opacity: 1;
  pointer-events: auto;
}
.modal {
  background: var(--surface-bg);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  box-shadow: var(--shadow);
  width: 90%;
  max-width: 400px;
  padding: 24px;
  transform: translateY(20px);
  transition: transform 0.2s;
}
.modal-backdrop.is-active .modal {
  transform: translateY(0);
}
.modal-title {
  margin: 0 0 8px;
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--text-primary);
}
.modal-body {
  margin-bottom: 24px;
  color: var(--text-secondary);
  font-size: 0.95rem;
  line-height: 1.5;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}
.modal-actions .button {
  min-width: 80px;
}
/* Button Loading Spinner */
.button.is-loading {
  position: relative;
  color: transparent !important;
  pointer-events: none;
  user-select: none;
}
.button.is-loading::after {
  content: '';
  position: absolute;
  width: 16px;
  height: 16px;
  top: 50%; left: 50%;
  margin-top: -8px; margin-left: -8px;
  border: 2px solid color-mix(in srgb, currentColor 30%, transparent);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: spin 0.6s linear infinite;
}
.button-outline.is-loading::after {
  border: 2px solid color-mix(in srgb, currentColor 25%, transparent);
  border-top-color: var(--primary-color);
}
@keyframes spin {
  to { transform: rotate(360deg); }
}
/* Secondary games: removable chips + an add row */
.secondary-games { display: grid; gap: 8px; }
.game-chips { display: flex; flex-wrap: wrap; gap: 6px; min-height: 30px; align-items: center; }
.game-chip { align-items: center; background: var(--surface-muted); border: 1px solid var(--line); border-radius: 999px; display: inline-flex; font-size: 12px; gap: 6px; padding: 4px 6px 4px 11px; }
.game-chip-remove { background: none; border: 0; border-radius: 50%; color: var(--muted); cursor: pointer; font-size: 15px; line-height: 1; padding: 0 4px; }
.game-chip-remove:hover { background: var(--line); color: var(--text); }
.game-add-row { display: flex; gap: 8px; }
.game-add-row input { flex: 1 1 auto; }

/* KPI header: the date range moved here from the deleted "ผลงาน & KPI" tab, so
   it now scopes the numbers that are visible from every tab. */
.kpi-period { align-items: center; border-top: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; padding-top: 10px; }
.kpi-period label { align-items: center; display: flex; font-size: 12px; gap: 6px; opacity: .85; }
.kpi-period input { font-size: 12px; padding: 4px 6px; }

/* Contract form: technical fields folded away, file attachable in place */
.contract-advanced { border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; }
.contract-advanced > summary { cursor: pointer; font-size: 13px; font-weight: 600; color: var(--muted); }
.contract-advanced[open] > summary { margin-bottom: 10px; }
.contract-advanced > .form-grid { margin-top: 4px; }
.contract-upload { display: grid; gap: 6px; margin-top: 8px; font-size: 12px; color: var(--muted); }
.contract-upload input[type="file"] { font-size: 12px; }
#contract-duration-hint { grid-column: 1 / -1; margin: 0; font-size: 12px; }

/* Skeleton Loading
   Built on --line/--surface-muted, which exist in BOTH themes. The previous
   version keyed off --border-color, which is only declared inside the dark
   theme block, so in light mode the bars had no background at all and the
   "loading" state was invisible -- the app looked frozen while it worked. */
.skeleton {
  background: var(--surface-muted);
  background-image: linear-gradient(90deg,
    color-mix(in srgb, var(--line) 55%, transparent) 25%,
    color-mix(in srgb, var(--line) 100%, transparent) 50%,
    color-mix(in srgb, var(--line) 55%, transparent) 75%);
  background-size: 200% 100%;
  animation: skeleton-loading 1.4s ease-in-out infinite;
  border-radius: 6px;
  display: block;
}
@keyframes skeleton-loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
/* Respect the OS setting: a constantly sweeping gradient is exactly the kind of
   motion people disable. The bars stay, they just hold still. */
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; }
}

.skeleton-line { height: 12px; width: 100%; }
.skeleton-line + .skeleton-line { margin-top: 8px; }
.skeleton-line.is-short { width: 45%; }
.skeleton-line.is-medium { width: 70%; }
.skeleton-line.is-title { height: 16px; width: 55%; }

/* Table cells: one bar per real column so the loading table keeps the same
   shape as the loaded one and the layout does not jump when data lands. */
.skeleton-cell { height: 12px; width: 80%; }
.skeleton-cell.is-narrow { width: 45%; }
tr.skeleton-tr td { padding: 14px 12px; }

.skeleton-panel { display: grid; gap: 14px; padding: 4px 0; }
.skeleton-panel .skeleton-field { display: grid; gap: 7px; }
.skeleton-panel .skeleton-field .skeleton-line:first-child { height: 10px; width: 30%; }
.skeleton-panel .skeleton-field .skeleton-line:last-child { height: 34px; width: 100%; }
.skeleton-cards { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.skeleton-cards .skeleton { height: 68px; }

/* Thin bar pinned to the top of the viewport whenever any request is in flight.
   Covers every update that is not a full page repaint -- saving a form, hitting
   refresh, switching a tab -- so the app never sits silent while it is busy. */
#activity-bar {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 3px;
  z-index: 9999;
  pointer-events: none;
  opacity: 0;
  transition: opacity .2s ease;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  background-size: 40% 100%;
  background-repeat: no-repeat;
}
#activity-bar.is-busy { opacity: 1; animation: activity-sweep 1.1s linear infinite; }
@keyframes activity-sweep {
  0% { background-position: -40% 0; }
  100% { background-position: 140% 0; }
}
@media (prefers-reduced-motion: reduce) {
  #activity-bar.is-busy { animation: none; background-position: 50% 0; }
}
/* Dark mode needs no per-component overrides any more: every status and badge
   below is written against a --*-soft token that already changes with the
   theme. What used to sit here was ~20 rules hand-maintained in parallel with
   their light-mode twins, plus a SECOND token block whose values silently beat
   the one at the top of this file. */
[data-theme="dark"] img, [data-theme="dark"] video { opacity: .88; }

/* Streamer Quick Actions & Data Hub Navigation */
/* .streamer-quick-actions was defined here as a neutral grey panel and then
   AGAIN further down as the amber warning card that actually renders. Only
   the second ever had any effect; this one and its dark twin were dead. */

.datahub-nav {
  display: flex;
  gap: 8px;
  margin-bottom: 1rem;
  border-bottom: 1px solid var(--border-color);
  padding-bottom: 12px;
  flex-wrap: wrap;
}

.datahub-tab-btn {
  border-radius: 6px;
  font-weight: 500;
  transition: all 0.2s ease;
}

/* Clickable contact subtext link */
a.row-subtext.cell-link-url {
  color: var(--accent);
  text-decoration: none;
  transition: color 0.15s ease, text-decoration 0.15s ease;
  cursor: pointer;
  display: block;
}
a.row-subtext.cell-link-url:hover {
  text-decoration: underline;
  color: var(--accent-hover);
}


/* ── Cloud mode: sign-in, roles, mobile ─────────────────────────────────── */

/* An explicit display here beats the browser's own [hidden] rule, so the
   attribute has to be honoured again or the overlay covers the app forever. */
.login-overlay[hidden] { display: none; }

.login-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: 1.5rem;
  background: var(--background-color);
}

.login-card {
  width: min(360px, 100%);
  display: grid;
  gap: 0.75rem;
  justify-items: stretch;
  text-align: center;
  padding: 2rem 1.5rem;
  border-radius: var(--radius, 14px);
  background: var(--surface);
  border: 1px solid var(--border-color);
  box-shadow: var(--shadow);
}

.login-card .brand-mark { justify-self: center; }
.login-card h2 { margin: 0; }
.login-card p { margin: 0; }

.login-error:empty { display: none; }
.login-error {
  margin: 0;
  font-size: 0.85rem;
  color: var(--danger);
}

/* Shown only when the app is talking to Google Sheets. */
.cloud-only { display: none; }
body.mode-cloud .cloud-only { display: inline-flex; }
body.mode-cloud #shutdown-app { display: none; }

/* The one feature still tied to the local Python server: importing from the
   Download folder on the PC's disk. Everything else runs on the cloud now. */
body.mode-cloud #marketing-import { display: none; }

/* Read-only presentation for viewers. The real enforcement is server side:
   a viewer's data never includes bank or payout figures, and Apps Script
   rejects their writes. */
body.role-viewer [data-add],
body.role-viewer [data-open-trash],
body.role-viewer [data-delete-streamer],
body.role-viewer [data-delete-payment],
body.role-viewer [data-delete-contract],
body.role-viewer [data-delete-content-link],
body.role-viewer [data-restore-trash],
body.role-viewer [data-custom-deactivate],
body.role-viewer #checklist-form,
body.role-viewer .drawer .button-primary,
body.role-viewer .drawer .button-danger,
body.role-viewer .content-link-save { display: none !important; }

body.role-viewer .drawer input,
body.role-viewer .drawer select,
body.role-viewer .drawer textarea {
  pointer-events: none;
  opacity: 0.75;
}

/* ── Touch and small screens ────────────────────────────────────────────── */

@media (max-width: 640px) {
  /* Full-screen drawer: a side panel at 375px leaves no room to read. */
  .drawer {
    width: 100%;
    max-width: 100%;
    inset: 0;
    border-radius: 0;
  }

  .data-table-container,
  #report-table-wrap,
  #marketing-content {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  .toolbar { flex-wrap: wrap; }
  .toolbar .search-input { flex: 1 1 100%; }

  .nav-item,
  .button,
  .icon-button { min-height: 44px; }

  .report-breakdowns,
  .split-panels { flex-direction: column; }
}

/* Payout report: the "fix this before you send it" banner has to be impossible
   to scroll past, and rows with gaps are tinted so they stand out in the table. */
.payout-warning { background: var(--warning-soft); border: 1px solid color-mix(in srgb, var(--warning) 45%, transparent); border-radius: 10px; margin: 14px 0; padding: 12px 14px; }
.payout-warning strong { display: block; margin-bottom: 6px; }
.payout-warning ul { margin: 0 0 6px; padding-left: 20px; }
.payout-warning li { font-size: 13px; margin: 2px 0; }
.payout-ok { background: var(--success-soft); border: 1px solid color-mix(in srgb, var(--success) 35%, transparent); border-radius: 10px; font-size: 13px; margin: 14px 0; padding: 10px 14px; }
.payout-flag { background: var(--warning); border-radius: 4px; color: var(--accent-contrast); font-size: 10px; font-weight: 700; margin-left: 6px; padding: 1px 5px; white-space: nowrap; }
tr.payout-total td { border-top: 2px solid var(--line); }
#report-table td, #report-table th { white-space: nowrap; }

/* Quick Actions is a gap list, not a fixed toolbar -- it vanishes when a
   streamer's profile is complete, so its presence always means something. */
.streamer-quick-actions { align-items: center; background: color-mix(in srgb, var(--warning) 10%, var(--surface)); border: 1px solid color-mix(in srgb, var(--warning) 35%, transparent); border-radius: 10px; display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0; padding: 10px 14px; }
.quick-actions-label { font-size: 13px; font-weight: 600; margin-right: 2px; }

/* Instalment editor */
.plan-row, .plan-quickfill { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
.plan-quickfill { margin-bottom: 10px; }
.plan-quickfill label, .plan-row label { display: grid; gap: 4px; font-size: 12px; }
.plan-table { border-collapse: collapse; width: 100%; margin-bottom: 8px; }
.plan-table th { color: var(--muted); font-size: 11px; font-weight: 600; padding: 4px 6px; text-align: left; }
.plan-table td { padding: 3px 6px; }
.plan-table input { min-height: 32px; width: 100%; }
.plan-index { color: var(--muted); font-size: 12px; width: 34px; }
.plan-remove { background: none; border: 0; color: var(--danger); font-size: 17px; line-height: 1; padding: 0 6px; }

/* Contract fulfilment.
   Cards, not a table: the drawer is narrow and on a phone it is narrower still,
   and the previous 3-column table overlapped its own cells into an unreadable
   mess. A card per period stacks safely at any width. */
.fulfil-panel { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; margin-bottom: 16px; padding: 14px; }
.fulfil-title { align-items: baseline; display: flex; flex-wrap: wrap; gap: 10px; }
.fulfil-title h3 { font-size: 15px; margin: 0; }
.fulfil-head p { color: var(--muted); font-size: 12px; margin: 4px 0 0; line-height: 1.5; }
.fulfil-rules { color: var(--text) !important; font-weight: 600; }
.fulfil-total strong { color: var(--text); }
.fulfil-stray { color: var(--warning) !important; }
.fulfil-empty { color: var(--muted); font-size: 13px; line-height: 1.6; }

/* A renewed streamer gets one panel per term, so each has to say which term it
   is and whether that term is still running. */
.fulfil-badge { background: var(--surface-muted); border: 1px solid var(--line); border-radius: 999px; font-size: 11px; font-weight: 700; padding: 2px 9px; }
.fulfil-phase { font-size: 11px; font-style: normal; opacity: .85; }
.fulfil-stray-all { color: var(--warning); font-size: 12px; margin: -6px 0 16px; }

/* Progress towards the whole term, one row per rule. The bar is what makes a
   lump-sum quota ("6 คลิปใน 90 วัน") legible: it is one target being filled
   over time, not a number to hit again every month. */
.fulfil-goals { display: grid; gap: 8px; margin-top: 10px; }
.fulfil-goal { display: grid; gap: 5px; }
.fulfil-goal-top { align-items: baseline; display: flex; gap: 8px; justify-content: space-between; }
.fulfil-goal-top span { font-size: 12px; font-weight: 600; }
.fulfil-goal-top small { color: var(--muted); font-size: 11px; font-weight: 400; margin-left: 6px; }
.fulfil-goal-top b { font-size: 13px; white-space: nowrap; }
.fulfil-bar { background: var(--surface-muted); border-radius: 999px; height: 6px; overflow: hidden; }
.fulfil-bar i { background: var(--muted); display: block; height: 100%; }
.fulfil-goal.is-met .fulfil-bar i { background: var(--success); }
.fulfil-goal.is-short .fulfil-bar i { background: var(--warning); }
.fulfil-goal.is-over .fulfil-bar i { background: var(--accent); }

.fulfil-cards { display: grid; gap: 10px; margin-top: 14px; }
.fulfil-card { background: var(--surface-muted); border: 1px solid var(--line); border-left: 3px solid var(--line); border-radius: 8px; display: grid; gap: 8px; padding: 10px 12px; }
.fulfil-card.is-current { border-left-color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, var(--surface)); }
.fulfil-card.is-future { opacity: .62; }
.fulfil-card-head { align-items: baseline; display: flex; flex-wrap: wrap; gap: 8px; }
.fulfil-card-head strong { font-size: 13px; }
.fulfil-card-head span { color: var(--muted); font-size: 12px; }
.fulfil-now { background: var(--accent); border-radius: 999px; color: var(--accent-contrast); font-size: 10px; font-style: normal; font-weight: 700; padding: 2px 8px; }

.fulfil-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.quota { align-items: center; border: 1px solid var(--line); border-radius: 999px; display: inline-flex; gap: 5px; font-size: 12px; padding: 4px 11px; }
.quota b { font-weight: 700; }
.quota i { font-size: 10px; font-style: normal; opacity: .7; }
.quota small { font-size: 10px; opacity: .8; }
.quota.is-met { background: color-mix(in srgb, var(--success) 15%, transparent); border-color: color-mix(in srgb, var(--success) 45%, transparent); }
.quota.is-short { background: color-mix(in srgb, var(--danger) 13%, transparent); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.quota.is-over { background: color-mix(in srgb, var(--accent) 15%, transparent); border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.quota.is-future { background: transparent; border-style: dashed; color: var(--muted); }
/* A lump-sum rule has no per-period target, so its chip reports, not judges --
   colouring it red or green would be inventing a deadline the contract never set. */
.quota.is-tally { background: var(--surface-muted); }

/* The verdict controls sit side by side when there is room and stack when there
   is not -- never overlapping, which is what the old fixed min-width caused. */
.fulfil-verdict { display: grid; gap: 6px; grid-template-columns: minmax(150px, auto) minmax(0, 1fr); }
.fulfil-verdict select, .fulfil-verdict input { font-size: 12px; min-height: 32px; max-width: none; min-width: 0; width: 100%; }
@media (max-width: 620px) { .fulfil-verdict { grid-template-columns: minmax(0, 1fr); } }
.fulfil-foot { margin: 12px 0 0; }

.deliverables { display: grid; gap: 8px; }
.quota u { font-size: 10px; text-decoration: none; opacity: .75; border-left: 1px solid currentColor; padding-left: 5px; }
/* The Download-folder importer needs a Download folder, so it is desktop-only;
   the upload button works in both runtimes and is no longer cloud-only. */
.local-only { display: inline-flex; }
body.mode-cloud .local-only { display: none; }
/* A coupon use that was reversed/cancelled is kept in the list as history but
   struck through, so the count and the list can never look contradictory. */
.coupon-void { opacity: .55; text-decoration: line-through; }

/* ── Spotlight cards ────────────────────────────────────────────────────────
 * A soft glow that follows the cursor inside a card (the "spotlight card"
 * effect). Done with a background-image layer rather than a ::before overlay on
 * purpose: an absolutely-positioned pseudo-element paints ABOVE in-flow text and
 * would need z-index/isolation juggling, while a background layer sits over the
 * background colour and under the content by definition -- and inherits the
 * card's border-radius for free.
 *
 * app.js keeps --spot-x/--spot-y in step with the pointer. Untouched, they
 * default to the card's centre, so the card looks normal with JS disabled.
 */
.metric,
.action-panel,
.fulfil-panel {
  background-image: radial-gradient(
    260px circle at var(--spot-x, 50%) var(--spot-y, 50%),
    color-mix(in srgb, var(--accent) 13%, transparent),
    transparent 62%
  );
  background-repeat: no-repeat;
  transition: box-shadow .25s ease, border-color .25s ease;
}
.metric:hover,
.action-panel:hover,
.fulfil-panel:hover {
  border-color: color-mix(in srgb, var(--accent) 42%, var(--line));
  box-shadow: 0 6px 20px -8px color-mix(in srgb, var(--accent) 45%, transparent);
}

/* The KPI card already paints its own gradient, so the glow is layered in front
   of it instead of replacing it. It is dark, so the glow is white, not accent. */
.kpi-header-card {
  background-image:
    radial-gradient(300px circle at var(--spot-x, 50%) var(--spot-y, 50%),
      color-mix(in srgb, var(--accent) 9%, transparent), transparent 60%);
    
}
.kpi-metric-item { transition: background-color .2s ease, transform .2s ease; }
.kpi-metric-item:hover { background: var(--hover-bg); transform: translateY(-1px); }

/* A glow that tracks the cursor is motion; honour the OS setting and drop it. */
@media (prefers-reduced-motion: reduce) {
  .metric, .action-panel, .fulfil-panel { background-image: none; transition: none; }
  .kpi-header-card { background-image: none; }
  .kpi-metric-item { transition: none; }
  .kpi-metric-item:hover { transform: none; }
}

/* ── Streamer toolbar: result count, clear-all, and the "ข้อมูลไม่ครบ" toggle ── */
.table-meta { align-items: center; display: flex; flex-wrap: wrap; gap: 10px; margin: -2px 0 10px; min-height: 22px; }
.table-count { color: var(--muted); font-size: 12px; }
.table-count strong { color: var(--text); }
.link-button { background: none; border: 0; color: var(--accent); font-size: 12px; padding: 0 0 0 6px; text-decoration: underline; }

/* A pressed filter reads as ON, so its state is visible without reading the label. */
.filter-toggle { background: var(--surface); border-color: var(--line); color: var(--muted); }
.filter-toggle:hover { background: var(--surface-muted); color: var(--text); }
.filter-toggle[aria-pressed="true"] {
  background: color-mix(in srgb, var(--warning) 16%, var(--surface));
  border-color: color-mix(in srgb, var(--warning) 55%, transparent);
  color: var(--text);
}

/* Rows are clickable, so they are now focusable too -- give the keyboard the
   same visible cue the mouse gets on hover. */
.data-table tbody tr[tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* Below ~720px the toolbar's selects would each claim a full row; let them share. */
@media (max-width: 720px) {
  .toolbar .search-input { flex: 1 1 100%; max-width: none; }
  .toolbar select { flex: 1 1 calc(50% - 4px); max-width: none; }
}

/* ── ไฮไลต์คำค้น ─────────────────────────────────────────────────────────── */
mark {
  background: color-mix(in srgb, var(--warning) 45%, transparent);
  border-radius: 3px;
  color: inherit;
  padding: 0 1px;
}

/* ── เลือกหลายแถว ────────────────────────────────────────────────────────── */
.select-cell { width: 38px; padding-left: 12px; padding-right: 0; }
.select-cell input { cursor: pointer; height: 16px; margin: 0; width: 16px; }
tbody tr.is-selected td { background: color-mix(in srgb, var(--accent) 9%, var(--surface)); }
tbody tr.is-selected:hover td { background: color-mix(in srgb, var(--accent) 14%, var(--surface)); }

.bulk-bar {
  align-items: center;
  background: color-mix(in srgb, var(--accent) 10%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 10px;
  padding: 10px 14px;
}
.bulk-bar[hidden] { display: none; }
.bulk-count { font-size: 13px; }
.bulk-field { align-items: center; color: var(--muted); display: flex; font-size: 12px; gap: 6px; }

/* ── มุมมองการ์ดบนจอแคบ ──────────────────────────────────────────────────────
 * Below 720px the table becomes one card per row: the head is hidden and each
 * cell prints its column name from data-label. Beats a table that can only be
 * read by dragging it sideways.
 */
@media (max-width: 720px) {
  .data-table-container { overflow: visible; }
  .data-table { width: 100%; }
  .data-table thead { display: none; }
  .data-table, .data-table tbody, .data-table tr, .data-table td { display: block; }

  .data-table tbody tr {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 10px;
    margin-bottom: 10px;
    padding: 6px 12px;
    position: relative;
  }
  .data-table tbody tr.is-selected { border-color: color-mix(in srgb, var(--accent) 55%, transparent); }

  .data-table tbody td {
    background: none;
    border-bottom: 1px solid var(--line);
    display: grid;
    gap: 8px;
    grid-template-columns: 40% 1fr;
    height: auto;
    min-height: 38px;
    padding: 7px 0;
    white-space: normal;
  }
  .data-table tbody td:last-child { border-bottom: 0; }
  .data-table tbody td::before {
    color: var(--muted);
    content: attr(data-label);
    font-size: 11px;
    font-weight: 600;
  }
  /* Cells with no heading (the tick box, and full-width empty/error states)
     must not reserve an empty label column. */
  .data-table tbody td:not([data-label]) { display: block; }
  .data-table tbody td:not([data-label])::before { content: none; }

  /* Sticky positioning is meaningless once rows are cards. */
  .data-table .sticky-cell { box-shadow: none; position: static; }
  .data-table tbody tr:hover td { background: none; }
  .row-subtext { max-width: none; }
  .cell-button { margin: 0; min-height: 0; padding: 0; }
  .select-cell { position: absolute; right: 8px; top: 8px; width: auto; padding: 0; }
}

/* "จ่ายเดือนนี้" — the roster doubles as the monthly payout checklist. */
.count-warning { color: var(--warning); }
.status-info { background: var(--info-soft); color: var(--info); }
