/* Teraverse ERP — design tokens + component styles
   Phase 1 foundation. Vanilla CSS scoped via .tv-* classnames.
   Brand: coral/orange gradient mark. Spec: Indigo primary.
   We honor both — Indigo for primary actions, brand gradient for the logo + accent moments.
*/

:root {
  /* Brand */
  --brand-coral: #ea5552;
  --brand-orange: #eb8c43;
  --brand-grad: linear-gradient(135deg, #ea5552 0%, #eb8c43 100%);

  /* Spec colors */
  --primary: #4F46E5;
  --primary-hover: #4338CA;
  --primary-50: #EEF2FF;
  --primary-100: #E0E7FF;
  --success: #10B981;
  --success-50: #ECFDF5;
  --warning: #F59E0B;
  --warning-50: #FFFBEB;
  --danger: #EF4444;
  --danger-50: #FEF2F2;
  --info: #0EA5E9;
  --info-50: #F0F9FF;

  /* Neutral */
  --bg: #F8FAFC;
  --card: #FFFFFF;
  --border: #E2E8F0;
  --border-strong: #CBD5E1;
  --fg-1: #0F172A;
  --fg-2: #475569;
  --fg-3: #64748B;
  --fg-4: #94A3B8;
  --hover: #F1F5F9;

  /* Sizing */
  --sidebar-w: 240px;
  --sidebar-w-collapsed: 64px;
  --topbar-h: 60px;
  --radius-sm: 6px;
  --radius: 8px;
  --radius-md: 10px;
  --radius-lg: 12px;
  --radius-xl: 16px;

  /* Shadow */
  --shadow-sm: 0 1px 2px 0 rgba(15, 23, 42, 0.04);
  --shadow: 0 1px 3px 0 rgba(15, 23, 42, 0.06), 0 1px 2px -1px rgba(15, 23, 42, 0.06);
  --shadow-md: 0 4px 12px -2px rgba(15, 23, 42, 0.08), 0 2px 4px -2px rgba(15, 23, 42, 0.04);
  --shadow-lg: 0 10px 25px -5px rgba(15, 23, 42, 0.1), 0 4px 10px -3px rgba(15, 23, 42, 0.05);

  /* Type — brand font is Kanit (uploaded) */
  --font-sans: "Kanit", "IBM Plex Sans Thai", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-num: "Kanit", "Inter", -apple-system, sans-serif;
}

/* ── Brand fonts: Kanit ──────────────── */
@font-face { font-family: "Kanit"; font-weight: 100; font-style: normal; font-display: swap; src: url("./fonts/kanit-100.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 100; font-style: italic; font-display: swap; src: url("./fonts/kanit-100-italic.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 200; font-style: normal; font-display: swap; src: url("./fonts/kanit-200.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 200; font-style: italic; font-display: swap; src: url("./fonts/kanit-200-italic.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 300; font-style: normal; font-display: swap; src: url("./fonts/kanit-300.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 300; font-style: italic; font-display: swap; src: url("./fonts/kanit-300-italic.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 400; font-style: normal; font-display: swap; src: url("./fonts/kanit-400.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 400; font-style: italic; font-display: swap; src: url("./fonts/kanit-400-italic.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 500; font-style: normal; font-display: swap; src: url("./fonts/kanit-500.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 500; font-style: italic; font-display: swap; src: url("./fonts/kanit-500-italic.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 600; font-style: normal; font-display: swap; src: url("./fonts/kanit-600.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 600; font-style: italic; font-display: swap; src: url("./fonts/kanit-600-italic.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 700; font-style: normal; font-display: swap; src: url("./fonts/kanit-700.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 700; font-style: italic; font-display: swap; src: url("./fonts/kanit-700-italic.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 800; font-style: normal; font-display: swap; src: url("./fonts/kanit-800.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 800; font-style: italic; font-display: swap; src: url("./fonts/kanit-800-italic.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 900; font-style: normal; font-display: swap; src: url("./fonts/kanit-900.ttf") format("truetype"); }
@font-face { font-family: "Kanit"; font-weight: 900; font-style: italic; font-display: swap; src: url("./fonts/kanit-900-italic.ttf") format("truetype"); }

[data-theme="dark"] {
  --bg: #0F172A;
  --card: #1E293B;
  --border: #334155;
  --border-strong: #475569;
  --fg-1: #F1F5F9;
  --fg-2: #CBD5E1;
  --fg-3: #94A3B8;
  --fg-4: #64748B;
  --hover: #1E293B;
  --primary-50: #312E81;
  --primary-100: #3730A3;
  --success-50: #064E3B;
  --warning-50: #78350F;
  --danger-50: #7F1D1D;
  --info-50: #0C4A6E;
  --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
  --shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.35);
  --shadow-md: 0 4px 12px -2px rgba(0, 0, 0, 0.4);
  --shadow-lg: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--fg-1);
  font-size: 14px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  letter-spacing: -0.005em;
}

button { font-family: inherit; cursor: pointer; border: none; background: none; padding: 0; color: inherit; }
input, select, textarea { font-family: inherit; }
.tv-num { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }

/* ── App shell ─────────────────────── */
.tv-app {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  grid-template-rows: var(--topbar-h) 1fr;
  grid-template-areas: "side topbar" "side main";
  min-height: 100vh;
  transition: grid-template-columns 250ms ease;
}
.tv-app.is-collapsed { grid-template-columns: var(--sidebar-w-collapsed) 1fr; }
.tv-main {
  grid-area: main;
  overflow-y: auto;
  padding: 24px 32px 48px;
}

/* ── Sidebar ───────────────────────── */
.tv-sidebar {
  grid-area: side;
  background: var(--card);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}
.tv-sidebar__brand {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 14px 14px 12px;
  border-bottom: 1px solid var(--border);
  height: var(--topbar-h);
}
.tv-sidebar__logo { width: 36px; height: 36px; flex: none; object-fit: contain; border-radius: 10px; }
.tv-sidebar__brand-text { display: flex; flex-direction: column; min-width: 0; }
.tv-sidebar__brand-name { font-weight: 700; font-size: 14px; line-height: 1.2; color: var(--fg-1); letter-spacing: 0; }
.tv-sidebar__brand-co { font-size: 10.5px; line-height: 1.35; color: var(--fg-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tv-sidebar.is-collapsed .tv-sidebar__brand { justify-content: center; padding: 16px 0; }

.tv-sidebar__scroll { flex: 1; overflow-y: auto; padding: 12px 10px 8px; }
.tv-navgroup { padding: 6px 0; }
.tv-navgroup__title {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-4);
  padding: 8px 10px 6px;
}
.tv-nav__item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border-radius: var(--radius);
  color: var(--fg-2);
  font-size: 13.5px;
  font-weight: 500;
  position: relative;
  transition: background 150ms ease, color 150ms ease;
}
.tv-nav__item:hover { background: var(--hover); color: var(--fg-1); }
.tv-nav__item.is-active {
  background: var(--primary-50);
  color: var(--primary);
  font-weight: 600;
}
.tv-nav__item.is-active::before {
  content: "";
  position: absolute;
  left: -10px;
  top: 6px;
  bottom: 6px;
  width: 3px;
  background: var(--primary);
  border-radius: 0 2px 2px 0;
}
.tv-nav__label { flex: 1; text-align: left; }
.tv-nav__badge {
  background: var(--primary);
  color: white;
  font-size: 10.5px;
  font-weight: 600;
  padding: 1px 6px;
  border-radius: 999px;
  min-width: 18px;
  text-align: center;
}
.tv-sidebar.is-collapsed .tv-nav__item { justify-content: center; padding: 10px; }
.tv-sidebar.is-collapsed .tv-nav__item.is-active::before { display: none; }
.tv-sidebar.is-collapsed .tv-navgroup__title { display: none; }

.tv-sidebar__collapse {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  color: var(--fg-3);
  font-size: 12.5px;
  font-weight: 500;
  transition: color 150ms;
}
.tv-sidebar__collapse:hover { color: var(--fg-1); }
.tv-sidebar.is-collapsed .tv-sidebar__collapse { justify-content: center; padding: 12px 0; }

/* ── TopBar ────────────────────────── */
.tv-topbar {
  grid-area: topbar;
  background: var(--card);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  position: sticky;
  top: 0;
  z-index: 30;
}
.tv-topbar__left, .tv-topbar__right { display: flex; align-items: center; gap: 8px; }
.tv-topbar__left { flex: 1; max-width: 480px; }

/* The phone-only way into the navigation. Above 900px the sidebar is a
   permanent column with its own "ย่อเมนู" toggle, so this would be a second
   control doing the same job; below it, the sidebar is off-canvas and takes
   its own toggle with it, leaving this the only one. */
.tv-topbar__menu {
  display: none;
  align-items: center;
  justify-content: center;
  width: 36px; height: 36px;
  flex: 0 0 auto;
  border-radius: var(--radius);
  color: var(--fg-2);
}
.tv-topbar__menu:hover { background: var(--hover); color: var(--fg-1); }

.tv-search {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 7px 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--fg-3);
  font-size: 13px;
  transition: border-color 150ms, background 150ms;
}
.tv-search:hover { background: var(--hover); border-color: var(--border-strong); }
.tv-search__placeholder { flex: 1; text-align: left; }
.tv-kbd {
  font-family: var(--font-num);
  font-size: 10.5px;
  padding: 2px 5px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--card);
  color: var(--fg-3);
  font-weight: 500;
}

.tv-iconbtn {
  position: relative;
  width: 36px;
  height: 36px;
  border-radius: var(--radius);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--fg-2);
  transition: background 150ms, color 150ms;
}
.tv-iconbtn:hover { background: var(--hover); color: var(--fg-1); }
.tv-iconbtn__badge {
  position: absolute;
  top: 4px; right: 4px;
  background: var(--danger);
  color: white;
  font-size: 9.5px;
  font-weight: 600;
  min-width: 16px;
  height: 16px;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 4px;
  border: 2px solid var(--card);
}

.tv-userbtn {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 10px 4px 4px;
  border-radius: var(--radius);
  transition: background 150ms;
}
.tv-userbtn:hover { background: var(--hover); }
.tv-userbtn__meta { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.2; }
.tv-userbtn__name { font-size: 13px; font-weight: 600; color: var(--fg-1); }
.tv-userbtn__role { font-size: 11px; color: var(--fg-3); }

/* ── Buttons ───────────────────────── */
.tv-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 500;
  border-radius: var(--radius);
  transition: background 150ms, border-color 150ms, color 150ms, transform 100ms;
  white-space: nowrap;
  border: 1px solid transparent;
}
.tv-btn:active:not(:disabled) { transform: scale(0.98); }
.tv-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.tv-btn--sm { padding: 5px 12px; font-size: 12.5px; }
.tv-btn--md { padding: 7px 14px; font-size: 13px; }
.tv-btn--lg { padding: 9px 18px; font-size: 14px; }

.tv-btn--primary { background: var(--primary); color: white; }
.tv-btn--primary:hover:not(:disabled) { background: var(--primary-hover); }
.tv-btn--secondary { background: var(--card); color: var(--fg-1); border-color: var(--border); }
.tv-btn--secondary:hover:not(:disabled) { background: var(--hover); border-color: var(--border-strong); }
.tv-btn--ghost { background: transparent; color: var(--fg-2); }
.tv-btn--ghost:hover:not(:disabled) { background: var(--hover); color: var(--fg-1); }
.tv-btn--danger { background: var(--danger); color: white; }
.tv-btn--danger:hover:not(:disabled) { background: #DC2626; }
.tv-btn--brand {
  background: var(--brand-grad);
  color: white;
}
.tv-btn--brand:hover:not(:disabled) { filter: brightness(0.95); }

.tv-spinner {
  width: 14px; height: 14px;
  border: 2px solid rgba(255,255,255,0.3);
  border-top-color: white;
  border-radius: 50%;
  animation: tv-spin 700ms linear infinite;
}
@keyframes tv-spin { to { transform: rotate(360deg); } }

/* ── Form fields ───────────────────── */
.tv-field { display: flex; flex-direction: column; gap: 6px; }
.tv-field__label { font-size: 12.5px; font-weight: 500; color: var(--fg-2); }
.tv-field__wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0 12px;
  transition: border-color 150ms, box-shadow 150ms;
}
.tv-field__wrap:focus-within {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-50);
}
.tv-field--error .tv-field__wrap { border-color: var(--danger); }
.tv-field--error .tv-field__wrap:focus-within { box-shadow: 0 0 0 3px var(--danger-50); }
.tv-field__input {
  flex: 1;
  border: none;
  outline: none;
  background: transparent;
  padding: 9px 0;
  font-size: 13.5px;
  color: var(--fg-1);
  min-width: 0;
}
.tv-field__input::placeholder { color: var(--fg-4); }
.tv-field__icon { color: var(--fg-3); flex: none; }
.tv-field__suffix { color: var(--fg-3); font-size: 12.5px; flex: none; }
.tv-field__select { appearance: none; cursor: pointer; padding-right: 0; }
.tv-field__msg { font-size: 12px; color: var(--fg-3); }
.tv-field__msg--error { color: var(--danger); }

/* ── Card ──────────────────────────── */
.tv-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  transition: transform 200ms ease, box-shadow 200ms ease, border-color 200ms ease;
}
.tv-card--padded { padding: 20px; }
.tv-card--hover:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--border-strong); }

/* ── Badge ─────────────────────────── */
.tv-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.5;
}
.tv-badge__dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.tv-btn--danger-ghost { color: var(--danger) !important; }
.tv-btn--danger-ghost:hover { background: var(--danger-50) !important; }

.tv-badge--neutral { background: var(--hover); color: var(--fg-2); }
.tv-badge--primary { background: var(--primary-50); color: var(--primary); }
.tv-badge--info { background: var(--info-50); color: var(--info); }
.tv-badge--success { background: var(--success-50); color: var(--success); }
.tv-badge--warning { background: var(--warning-50); color: var(--warning); }
.tv-badge--danger { background: var(--danger-50); color: var(--danger); }
[data-theme="dark"] .tv-badge--info { color: #7DD3FC; }
[data-theme="dark"] .tv-badge--success { color: #6EE7B7; }
[data-theme="dark"] .tv-badge--warning { color: #FCD34D; }
[data-theme="dark"] .tv-badge--danger { color: #FCA5A5; }

/* ── Avatar ────────────────────────── */
.tv-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: white;
  font-weight: 600;
  font-family: var(--font-sans);
  flex: none;
}

/* ── Toast ─────────────────────────── */
.tv-toast-stack {
  position: fixed;
  top: 20px; right: 20px;
  z-index: 100;
  display: flex;
  flex-direction: column;
  gap: 10px;
  pointer-events: none;
}
.tv-toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  min-width: 280px;
  max-width: 380px;
  animation: tv-toast-in 300ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes tv-toast-in {
  from { opacity: 0; transform: translateX(20px); }
  to { opacity: 1; transform: translateX(0); }
}
.tv-toast--success { border-left: 3px solid var(--success); }
.tv-toast--success > svg:first-child { color: var(--success); }
.tv-toast--danger { border-left: 3px solid var(--danger); }
.tv-toast--danger > svg:first-child { color: var(--danger); }
.tv-toast--warning { border-left: 3px solid var(--warning); }
.tv-toast--warning > svg:first-child { color: var(--warning); }
.tv-toast--info { border-left: 3px solid var(--info); }
.tv-toast--info > svg:first-child { color: var(--info); }
.tv-toast__body { flex: 1; min-width: 0; }
.tv-toast__title { font-weight: 600; font-size: 13px; color: var(--fg-1); }
.tv-toast__msg { font-size: 12.5px; color: var(--fg-2); margin-top: 2px; }
.tv-span-2 { grid-column: span 2; }

/* ── Modal & Drawer ────────────────── */
.tv-modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, 0.4);
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 80;
  animation: tv-fade 200ms ease;
}
@keyframes tv-fade { from { opacity: 0; } to { opacity: 1; } }
.tv-modal {
  background: var(--card);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  max-height: 85vh;
  width: 90vw;
  animation: tv-modal-in 250ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes tv-modal-in {
  from { opacity: 0; transform: scale(0.96) translateY(8px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}
.tv-modal--sm { max-width: 420px; }
.tv-modal--md { max-width: 560px; }
.tv-modal--lg { max-width: 800px; }
.tv-modal__head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
}
.tv-modal__head h3 { margin: 0; font-size: 15px; font-weight: 600; }
.tv-modal__close {
  width: 28px; height: 28px;
  border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center;
  color: var(--fg-3);
  transition: background 150ms;
}
.tv-modal__close:hover { background: var(--hover); color: var(--fg-1); }
.tv-modal__body { padding: 20px; overflow-y: auto; }
.tv-modal__foot {
  padding: 12px 20px;
  border-top: 1px solid var(--border);
  display: flex; justify-content: flex-end; gap: 8px;
}

.tv-drawer-backdrop {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, 0.4);
  z-index: 70;
  opacity: 0; pointer-events: none;
  transition: opacity 250ms ease;
}
.tv-drawer-backdrop.is-open { opacity: 1; pointer-events: auto; }
.tv-drawer {
  position: fixed;
  top: 0; bottom: 0;
  background: var(--card);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  z-index: 75;
  transform: translateX(100%);
  transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);
}
.tv-drawer--right { right: 0; }
.tv-drawer--right.is-open { transform: translateX(0); }
.tv-drawer__body { flex: 1; }

/* ── Dropdown ──────────────────────── */
.tv-dropdown { position: relative; display: inline-flex; }
.tv-dropdown__menu {
  position: absolute;
  top: calc(100% + 6px);
  min-width: 220px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 6px;
  z-index: 50;
  opacity: 0;
  transform: scale(0.96) translateY(-4px);
  pointer-events: none;
  transform-origin: top right;
  transition: opacity 150ms, transform 150ms;
}
.tv-dropdown__menu--right { right: 0; }
.tv-dropdown__menu--left { left: 0; transform-origin: top left; }

/* Rendered into <body> and pinned to its trigger, so no ancestor's
   `overflow: hidden` can clip it — `.tv-tablewrap` used to swallow the row
   menus on the last rows of every table. `left`/`top` come from the component,
   which also flips the menu above the trigger when there is no room below. */
.tv-dropdown__menu--floating {
  position: fixed;
  top: auto;
  right: auto;
  z-index: 80;
  overflow-y: auto;
}
.tv-dropdown__menu.is-open {
  opacity: 1;
  transform: scale(1) translateY(0);
  pointer-events: auto;
}
.tv-dropdown__item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: var(--fg-1);
  text-align: left;
  transition: background 120ms;
}
.tv-dropdown__item > span:first-of-type { flex: 1; }
.tv-dropdown__item:hover { background: var(--hover); }
.tv-dropdown__item:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.tv-dropdown__item:disabled:hover { background: transparent; }
.tv-dropdown__item--danger { color: var(--danger); }
.tv-dropdown__item--danger:hover { background: var(--danger-50); }
.tv-dropdown__item svg { color: var(--fg-3); flex: none; }
.tv-dropdown__item--danger svg { color: var(--danger); }
.tv-dropdown__item.is-active { background: var(--primary-50); color: var(--primary); }
.tv-dropdown__item.is-active svg { color: var(--primary); }
.tv-dropdown__divider { height: 1px; background: var(--border); margin: 4px 0; }
.tv-dropdown__header {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-4);
  padding: 8px 10px 4px;
}

/* ── Editable status pill trigger ────── */
.tv-statuspill-trigger {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 6px 2px 2px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
  transition: background 120ms, border-color 120ms;
}
.tv-statuspill-trigger:hover {
  background: var(--hover);
  border-color: var(--border);
}
.tv-statuspill-trigger:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* ── Notifications dropdown ────────── */
.tv-notif { width: 360px; padding: 0; }
.tv-notif__head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
}
.tv-notif__head strong { font-size: 13.5px; }
.tv-notif__list { max-height: 340px; overflow-y: auto; padding: 4px 0; }
.tv-notif__item {
  display: flex;
  gap: 10px;
  padding: 10px 14px;
  position: relative;
  transition: background 120ms;
  width: 100%;
  border: 0;
  background: transparent;
  text-align: left;
  color: inherit;
  cursor: pointer;
  font: inherit;
}
.tv-notif__item:hover { background: var(--hover); }
.tv-notif__item.is-unread { background: linear-gradient(90deg, var(--primary-50), transparent 70%); }
[data-theme="dark"] .tv-notif__item.is-unread { background: linear-gradient(90deg, rgba(79,70,229,0.18), transparent 70%); }
.tv-notif__icon {
  width: 28px; height: 28px;
  border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center;
  flex: none;
}
.tv-notif__icon--doc { background: var(--info-50); color: var(--info); }
.tv-notif__icon--finance { background: var(--success-50); color: var(--success); }
.tv-notif__icon--system { background: var(--warning-50); color: var(--warning); }
/* min-width:0 so a long notification title wraps instead of forcing the
   dropdown wider than its own panel. */
.tv-notif__body { flex: 1; min-width: 0; text-align: left; padding-right: 12px; }
.tv-notif__title { font-size: 13px; color: var(--fg-1); line-height: 1.4; }
.tv-notif__time { font-size: 11.5px; color: var(--fg-3); margin-top: 3px; }
.tv-notif__dot { position: absolute; right: 14px; top: 16px; width: 7px; height: 7px; background: var(--primary); border-radius: 50%; }
.tv-notif__foot { padding: 10px 14px; border-top: 1px solid var(--border); text-align: center; }
.tv-link { color: var(--primary); font-size: 12.5px; font-weight: 500; }
.tv-link:hover { text-decoration: underline; }

/* ── Table ─────────────────────────── */
.tv-tablewrap {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  /* auto, not hidden: a table wider than its container used to be cut off with
     no way to reach the rest of the columns, which on a phone hid whole
     columns silently. The row menus are portalled out (see
     .tv-dropdown__menu--floating) so this no longer clips them either. */
  overflow-x: auto;
}
.tv-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.tv-table thead th {
  text-align: left;
  font-weight: 600;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--fg-3);
  padding: 10px 14px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.tv-table__sortbtn {
  display: inline-flex; align-items: center; gap: 5px;
  font: inherit;
  color: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
}
.tv-table__sortbtn:hover { color: var(--fg-1); }
.tv-table tbody td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  color: var(--fg-1);
  vertical-align: middle;
}
.tv-table tbody tr:last-child td { border-bottom: none; }
.tv-table__row--click { cursor: pointer; transition: background 120ms; }
.tv-table__row--click:hover { background: var(--hover); }
.tv-table__empty { text-align: center; color: var(--fg-3); padding: 40px 14px; font-size: 13px; }

/* ── Tabs ──────────────────────────── */
.tv-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
}
/* .tv-tab is the hand-rolled variant used by the Users and Profile pages. */
.tv-tabs__item, .tv-tab {
  display: flex; align-items: center; gap: 6px;
  padding: 10px 14px;
  font-size: 13px;
  font-weight: 500;
  color: var(--fg-3);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color 150ms, border-color 150ms;
}
.tv-tabs__item:hover, .tv-tab:hover { color: var(--fg-1); }
.tv-tabs__item.is-active, .tv-tab.is-active {
  color: var(--primary);
  border-bottom-color: var(--primary);
  font-weight: 600;
}
.tv-tabs__count {
  font-size: 11px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--hover);
  color: var(--fg-3);
}
.tv-tabs__item.is-active .tv-tabs__count { background: var(--primary-50); color: var(--primary); }

/* ── Toggle ────────────────────────── */
.tv-toggle { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; }
.tv-toggle input { position: absolute; opacity: 0; pointer-events: none; }
.tv-toggle__track {
  width: 36px; height: 20px;
  background: var(--border-strong);
  border-radius: 999px;
  position: relative;
  transition: background 200ms;
}
.tv-toggle__thumb {
  position: absolute;
  width: 16px; height: 16px;
  background: white;
  border-radius: 50%;
  top: 2px; left: 2px;
  box-shadow: var(--shadow-sm);
  transition: transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.tv-toggle input:checked + .tv-toggle__track { background: var(--primary); }
.tv-toggle input:checked + .tv-toggle__track .tv-toggle__thumb { transform: translateX(16px); }
.tv-toggle__label { font-size: 13px; color: var(--fg-1); }
.tv-toggle.is-disabled { cursor: not-allowed; opacity: 0.5; }

/* ── Skeleton ──────────────────────── */
.tv-skeleton {
  background: linear-gradient(90deg, var(--hover) 0%, var(--border) 50%, var(--hover) 100%);
  background-size: 200% 100%;
  animation: tv-shimmer 1.4s ease-in-out infinite;
  border-radius: var(--radius-sm);
  display: inline-block;
}
@keyframes tv-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ── Page header ───────────────────── */
.tv-pagehead { margin-bottom: 24px; }
.tv-crumbs { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--fg-3); margin-bottom: 8px; }
.tv-crumbs__sep { color: var(--fg-4); }
.tv-crumbs__current { color: var(--fg-1); font-weight: 500; }
.tv-crumbs__link {
  padding: 0;
  color: var(--fg-3);
  font: inherit;
  background: transparent;
  border: 0;
  cursor: pointer;
}
.tv-crumbs__link:hover { color: var(--primary); text-decoration: underline; }
.tv-pagehead__row { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; }
.tv-pagehead__title { margin: 0; font-size: 22px; font-weight: 600; letter-spacing: -0.015em; color: var(--fg-1); }
.tv-pagehead__desc { margin: 4px 0 0; color: var(--fg-3); font-size: 13.5px; }
.tv-pagehead__actions { display: flex; gap: 8px; }

/* ── Command palette ───────────────── */
.tv-cmd-backdrop { align-items: flex-start; padding-top: 12vh; }
.tv-cmd {
  width: 90vw;
  max-width: 560px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  animation: tv-modal-in 220ms cubic-bezier(0.16, 1, 0.3, 1);
}
.tv-cmd__head {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
}
.tv-cmd__head svg { color: var(--fg-3); }
.tv-cmd__head input {
  flex: 1;
  border: none; outline: none;
  background: transparent;
  font-size: 14px;
  color: var(--fg-1);
}
.tv-cmd__list { max-height: 50vh; overflow-y: auto; padding: 6px; }
.tv-cmd__item {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: var(--fg-1);
  text-align: left;
  transition: background 120ms;
}
.tv-cmd__item:hover { background: var(--hover); }
.tv-cmd__item svg { color: var(--fg-3); }
.tv-cmd__label { flex: 1; }
.tv-cmd__kind { font-size: 11px; color: var(--fg-4); }
.tv-cmd__empty { padding: 24px; text-align: center; color: var(--fg-3); font-size: 13px; }

/* ── Dashboard helpers ─────────────── */
.tv-grid-kpi {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-bottom: 24px;
}
.tv-kpi__label { font-size: 12.5px; color: var(--fg-3); font-weight: 500; }
.tv-kpi__value { font-size: 26px; font-weight: 600; letter-spacing: -0.02em; color: var(--fg-1); margin-top: 4px; font-family: var(--font-num); font-variant-numeric: tabular-nums; }
.tv-kpi__delta { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600; margin-top: 10px; padding: 2px 7px; border-radius: 999px; }
.tv-kpi__delta--up { background: var(--success-50); color: var(--success); }
.tv-kpi__delta--down { background: var(--danger-50); color: var(--danger); }
.tv-kpi__icon {
  width: 36px; height: 36px;
  border-radius: var(--radius);
  display: flex; align-items: center; justify-content: center;
  background: var(--primary-50);
  color: var(--primary);
}
.tv-kpi__top { display: flex; justify-content: space-between; align-items: flex-start; }

.tv-dash-grid {
  display: grid;
  /* minmax(0, …) rather than bare fr. A bare `2fr 1fr` floors each track at its
     item's min-content, and the เอกสารล่าสุด card holds a table whose
     min-content is ~510px — so on a phone the track ignored the 1fr collapse
     below and rendered 510px wide inside a 347px page, pushing ยอดรวม, สถานะ
     and the row menu off the screen with no way to scroll to them. The table
     already has its own .tv-tablewrap scroller; this just lets the track be
     narrower than the table so that scroller is the thing that scrolls.
     On desktop the tracks are already wider than min-content, so nothing about
     the existing layout changes. */
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 16px;
  margin-bottom: 24px;
}
.tv-section-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--fg-1);
  margin: 0 0 4px;
}
.tv-section-sub { font-size: 12.5px; color: var(--fg-3); margin: 0 0 16px; }

/* ── Login screen ────────────────────
   Its own palette, scoped to .tv-login: raspberry #E8385B → amber #E87E47.
   Overriding --primary here rather than at :root means the shared primitives
   (Button, focus rings, links, the contact Modal rendered inside this tree)
   pick the login colours up without a second set of classes, and the rest of
   the app keeps its indigo. */
.tv-login {
  --tv-login-1: #E8385B;
  --tv-login-2: #E87E47;
  --tv-login-grad: linear-gradient(135deg, #E8385B 0%, #E8595199 45%, #E87E47 100%);
  --primary: #E8385B;
  --primary-hover: #D22B4D;
  --primary-50: #FDECEF;
  --primary-100: #FBD8DE;

  min-height: 100vh;
  display: grid;
  grid-template-columns: 1fr 1fr;
  background: var(--bg);
}
[data-theme="dark"] .tv-login {
  --primary-50: #4A1524;
  --primary-100: #5E1B2E;
}
.tv-login__form-side {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px;
  background: var(--card);
}
/* Set-password / expired-link screen: one centred column, no brand panel — it
   is a single task, not a front door. The brand tint stays as a top edge so the
   page still reads as part of the product. */
.tv-login--single { grid-template-columns: 1fr; }
.tv-login--single .tv-login__form-side {
  border-top: 3px solid transparent;
  border-image: var(--tv-login-grad) 1;
}
.tv-login__notice {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 14px 16px;
  border-radius: var(--radius);
  font-size: 13px; line-height: 1.6;
  background: var(--primary-50);
  color: var(--fg-2);
  border: 1px solid var(--primary-100);
}
.tv-login__notice--error { color: var(--fg-1); }
.tv-login__notice svg { flex: none; margin-top: 2px; color: var(--tv-login-1); }
.tv-login__notice strong { display: block; margin-bottom: 4px; color: var(--fg-1); }
.tv-login__notice p { margin: 0 0 6px; }
.tv-login__notice p:last-child { margin-bottom: 0; }
.tv-login__form-wrap { width: 100%; max-width: 400px; }
.tv-login__brand { display: flex; gap: 12px; align-items: center; margin-bottom: 48px; }
.tv-login__brand img { width: 36px; height: 36px; object-fit: contain; }
.tv-login__brand-name { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; color: var(--fg-1); }
.tv-login__brand-co { font-size: 11.5px; color: var(--fg-3); }
.tv-login__head h1 { margin: 0 0 8px; font-size: 26px; font-weight: 600; letter-spacing: -0.02em; }
.tv-login__head p { margin: 0 0 32px; color: var(--fg-3); font-size: 14px; }
.tv-login__form { display: flex; flex-direction: column; gap: 16px; }
.tv-login__form > * {
  animation: tv-stagger-in 400ms cubic-bezier(0.16, 1, 0.3, 1) backwards;
}
.tv-login__form > *:nth-child(1) { animation-delay: 60ms; }
.tv-login__form > *:nth-child(2) { animation-delay: 120ms; }
.tv-login__form > *:nth-child(3) { animation-delay: 180ms; }
.tv-login__form > *:nth-child(4) { animation-delay: 240ms; }
.tv-login__form > *:nth-child(5) { animation-delay: 300ms; }
.tv-login__form > *:nth-child(6) { animation-delay: 360ms; }
@keyframes tv-stagger-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}
/* The one call to action on the page, so it carries the full gradient and its
   own hover lift rather than borrowing .tv-btn--primary's flat fill. */
.tv-login__submit {
  margin-top: 8px;
  width: 100%;
  display: flex; align-items: center; justify-content: center; gap: 9px;
  padding: 14px 20px;
  border: 0;
  border-radius: 12px;
  background: var(--tv-login-grad);
  background-size: 160% 100%;
  color: white;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.01em;
  cursor: pointer;
  box-shadow: 0 6px 18px -6px rgba(232, 56, 91, 0.55);
  transition: transform 140ms ease, box-shadow 200ms ease, background-position 400ms ease;
}
.tv-login__submit:hover:not(:disabled) {
  background-position: 100% 0;
  transform: translateY(-1px);
  box-shadow: 0 12px 26px -8px rgba(232, 56, 91, 0.6);
}
.tv-login__submit:active:not(:disabled) { transform: translateY(0); box-shadow: 0 4px 12px -6px rgba(232, 56, 91, 0.5); }
.tv-login__submit:focus-visible { outline: 2px solid var(--tv-login-1); outline-offset: 3px; }
.tv-login__submit:disabled { opacity: 0.72; cursor: default; }
.tv-login__submit .tv-spinner { border-top-color: white; border-color: rgba(255,255,255,0.35); }

/* Text link in the login palette — used by the ติดต่อผู้ดูแลระบบ trigger and by
   the phone/email links inside the contact dialog. */
.tv-login__link {
  background: none; border: 0; padding: 0;
  font: inherit; color: var(--tv-login-1);
  font-weight: 500; cursor: pointer;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 140ms ease, color 140ms ease;
}
.tv-login__link:hover { color: var(--tv-login-2); border-bottom-color: currentColor; }
.tv-login__foot { text-align: center; color: var(--fg-3); font-size: 13px; margin-top: 32px; }

/* Contact channels in the ติดต่อผู้ดูแลระบบ dialog */
.tv-contact-list { display: flex; flex-direction: column; gap: 2px; }
.tv-contact-row {
  display: grid;
  grid-template-columns: 30px 82px 1fr;
  align-items: center;
  gap: 10px;
  padding: 11px 12px;
  border-radius: var(--radius);
  background: var(--bg);
}
.tv-contact-row__icon {
  width: 30px; height: 30px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center;
  background: var(--primary-50); color: var(--tv-login-1);
}
.tv-contact-row__label { font-size: 12.5px; color: var(--fg-3); }
.tv-contact-row__value { font-size: 13.5px; font-weight: 500; color: var(--fg-1); word-break: break-word; }
.tv-contact-row__value--empty { color: var(--fg-4); font-weight: 400; font-style: italic; }

.tv-login__brand-side {
  position: relative;
  /* Deep plum base so white text keeps its contrast, with the two brand
     colours carried by the glow layer below rather than the base fill — a full
     #E8385B → #E87E47 background is too bright to read body copy on. */
  background: linear-gradient(140deg, #5B0F23 0%, #96153C 45%, #C43A46 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 64px;
  overflow: hidden;
  color: white;
}
.tv-login__brand-pattern {
  position: absolute; inset: 0;
  background-image:
    radial-gradient(circle at 18% 26%, rgba(232, 56, 91, 0.55) 0%, transparent 42%),
    radial-gradient(circle at 82% 72%, rgba(232, 126, 71, 0.5) 0%, transparent 46%),
    radial-gradient(circle at 55% 45%, rgba(255, 255, 255, 0.07) 0%, transparent 58%);
}
.tv-login__brand-pattern::after {
  content: "";
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,0.04) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.04) 1px, transparent 1px);
  background-size: 40px 40px;
  mask-image: radial-gradient(ellipse at center, black 30%, transparent 80%);
}
.tv-login__brand-content { position: relative; max-width: 460px; }
.tv-login__brand-mark { width: 64px; height: 64px; object-fit: contain; margin-bottom: 24px; filter: drop-shadow(0 8px 24px rgba(232, 56, 91, 0.55)); }
.tv-login__brand-content h2 { margin: 0 0 16px; font-size: 36px; font-weight: 600; letter-spacing: -0.02em; line-height: 1.15; }
.tv-login__brand-content > p { margin: 0 0 32px; color: rgba(255,255,255,0.75); font-size: 15px; line-height: 1.6; }
.tv-login__features { display: flex; flex-direction: column; gap: 14px; margin-bottom: 36px; }
.tv-login__feat { display: flex; gap: 12px; align-items: flex-start; }
.tv-login__feat-icon {
  width: 32px; height: 32px;
  border-radius: 8px;
  background: rgba(255,255,255,0.1);
  border: 1px solid rgba(255,255,255,0.15);
  display: flex; align-items: center; justify-content: center;
  flex: none;
  color: rgba(255,255,255,0.95);
}
.tv-login__feat-title { font-size: 13.5px; font-weight: 600; }
.tv-login__feat-desc { font-size: 12.5px; color: rgba(255,255,255,0.6); margin-top: 1px; }
.tv-login__brand-foot {
  display: flex; flex-direction: column; gap: 3px;
  padding: 16px 20px;
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.14);
  border-left: 3px solid var(--tv-login-2);
  border-radius: var(--radius-lg);
  backdrop-filter: blur(8px);
}
.tv-login__brand-foot-label {
  font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase;
  color: rgba(255,255,255,0.55);
}
.tv-login__brand-foot-name { font-size: 15px; font-weight: 600; color: white; }

@media (max-width: 960px) {
  .tv-login { grid-template-columns: 1fr; }
  .tv-login__brand-side { display: none; }
}

/* ── Company info / forms ──────────── */
.tv-add-row {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 14px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  color: var(--fg-3);
  font-size: 13px;
  font-weight: 500;
  background: transparent;
  transition: border-color 150ms, color 150ms, background 150ms;
}
.tv-add-row:hover {
  border-color: var(--primary);
  color: var(--primary);
  background: var(--primary-50);
}

.tv-uploader {
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  height: 160px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px;
  background: var(--bg);
  transition: border-color 150ms, background 150ms;
}
.tv-uploader:hover { border-color: var(--primary); background: var(--primary-50); }

.tv-doctable {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  max-width: 880px;
}
.tv-doctable__head, .tv-doctable__row {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1.4fr 1.4fr 0.9fr;
  gap: 12px;
  padding: 10px 14px;
  align-items: center;
}
.tv-doctable__head {
  background: var(--bg);
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--fg-3);
  border-bottom: 1px solid var(--border);
}
.tv-doctable__row { border-bottom: 1px solid var(--border); font-size: 13px; }
.tv-doctable__row:last-child { border-bottom: none; }

/* ── List toolbar / pagination / empty / summary ── */
.tv-listbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.tv-listbar__search { flex: 1; min-width: 240px; max-width: 360px; }
.tv-listbar__search .tv-field { gap: 0; }
.tv-listbar__filters { display: flex; gap: 8px; flex-wrap: wrap; }
.tv-listbar__filters .tv-field { gap: 0; min-width: 140px; }

.tv-pagination {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  gap: 12px;
  flex-wrap: wrap;
}
.tv-pagination__summary { font-size: 12.5px; color: var(--fg-3); }
.tv-pagination__pages { display: flex; align-items: center; gap: 4px; }
.tv-pagination__btn {
  min-width: 30px;
  height: 30px;
  padding: 0 8px;
  border-radius: var(--radius-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--fg-2);
  transition: background 120ms, color 120ms;
}
.tv-pagination__btn:hover:not(:disabled):not(.is-active) { background: var(--hover); color: var(--fg-1); }
.tv-pagination__btn.is-active { background: var(--primary); color: white; }
.tv-pagination__btn:disabled { opacity: 0.4; cursor: not-allowed; }
.tv-pagination__dots { padding: 0 4px; color: var(--fg-3); font-size: 12px; }

.tv-empty {
  text-align: center;
  padding: 56px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.tv-empty__icon {
  width: 56px; height: 56px;
  border-radius: 14px;
  background: var(--primary-50);
  color: var(--primary);
  display: flex; align-items: center; justify-content: center;
}
.tv-empty__title { margin: 0; font-size: 15px; font-weight: 600; }
.tv-empty__desc { margin: 0; color: var(--fg-3); font-size: 13.5px; max-width: 360px; }

.tv-summary-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}
.tv-summary-tile {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
}
.tv-summary-tile__head { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; }
.tv-summary-tile__ico {
  width: 22px; height: 22px;
  border-radius: 6px;
  display: flex; align-items: center; justify-content: center;
}
.tv-summary-tile__ico--info { background: var(--info-50); color: var(--info); }
.tv-summary-tile__ico--success { background: var(--success-50); color: var(--success); }
.tv-summary-tile__ico--warning { background: var(--warning-50); color: var(--warning); }
.tv-summary-tile__ico--danger { background: var(--danger-50); color: var(--danger); }
.tv-summary-tile__ico--neutral { background: var(--hover); color: var(--fg-3); }
.tv-summary-tile__label { font-size: 12px; color: var(--fg-3); font-weight: 500; }
.tv-summary-tile__value { font-size: 20px; font-weight: 600; color: var(--fg-1); letter-spacing: -0.01em; }
.tv-summary-tile__sub { font-size: 11.5px; color: var(--fg-3); margin-top: 2px; }

.tv-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.tv-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--card);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--fg-2);
  transition: all 150ms;
}
.tv-chip:hover { border-color: var(--border-strong); color: var(--fg-1); }
.tv-chip.is-active {
  background: var(--primary);
  border-color: var(--primary);
  color: white;
}
.tv-chip__count {
  font-size: 11px;
  background: var(--hover);
  color: var(--fg-3);
  padding: 1px 6px;
  border-radius: 999px;
}
.tv-chip.is-active .tv-chip__count { background: rgba(255,255,255,0.2); color: white; }

/* ── Pay methods (radio cards) ── */
.tv-pay-methods {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 8px;
}
.tv-pay-method {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  padding: 14px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  color: var(--fg-2);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: all 150ms;
}
.tv-pay-method:hover { border-color: var(--border-strong); color: var(--fg-1); }
.tv-pay-method.is-active {
  border-color: var(--primary);
  background: var(--primary-50);
  color: var(--primary);
  font-weight: 600;
}

/* ── Info banner (icon + text) ── */
.tv-info-banner {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 10px 12px;
  background: var(--info-50);
  border: 1px solid color-mix(in srgb, var(--info) 25%, transparent);
  border-radius: var(--radius);
  font-size: 12.5px;
  color: var(--fg-2);
  line-height: 1.5;
}
.tv-info-banner > svg { color: var(--info); flex: none; margin-top: 2px; }

/* ── Withholding rate summary (ค่าใช้จ่าย → ภาษีหัก ณ ที่จ่าย) ── */
.tv-wht-rates {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
  margin-top: 12px;
}
.tv-wht-rate {
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
}
.tv-wht-rate.is-highlight {
  border-color: color-mix(in srgb, var(--warning) 45%, transparent);
  background: var(--warning-50);
}
.tv-wht-rate__num { font-size: 18px; font-weight: 600; color: var(--warning); letter-spacing: -0.01em; }
.tv-wht-rate__label { font-size: 12px; color: var(--fg-3); margin-top: 2px; }
.tv-wht-rate__amt { font-size: 13.5px; font-weight: 600; color: var(--fg-1); margin-top: 6px; }

/* ── Payment voucher tab (เตรียมจ่ายเงิน) ── */
.tv-payvoucher-groups {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 12px;
}
.tv-payvoucher-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}
.tv-payvoucher-items { display: flex; flex-direction: column; gap: 2px; margin-top: 8px; }
.tv-payvoucher-item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 8px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background 120ms;
}
.tv-payvoucher-item:hover { background: var(--hover); }
.tv-payvoucher-item input { margin-top: 3px; accent-color: var(--primary); flex: none; }
/* The confirm dialog's headline figures — the amount about to leave the bank
   account, so it is the one thing in the modal that must be unmissable. */
.tv-payment-summary {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* ── Customer card (in quotation editor) ── */
.tv-customer-card {
  display: flex; align-items: center; gap: 12px;
  padding: 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* ── Product thumb ── */
.tv-prod-thumb {
  width: 32px; height: 32px;
  border-radius: var(--radius-sm);
  display: inline-flex; align-items: center; justify-content: center;
  flex: none;
}
.tv-prod-thumb--lg { width: 48px; height: 48px; border-radius: var(--radius); }

/* ── Stock bar ── */
.tv-stockbar {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px;
}
.tv-stockbar__track { width: 60px; height: 4px; background: var(--hover); border-radius: 999px; overflow: hidden; }
.tv-stockbar__fill { height: 100%; background: var(--success); border-radius: inherit; transition: width 250ms; }

/* ── Note (info card) ── */
.tv-note {
  padding: 10px 12px;
  background: var(--warning-50);
  border-left: 3px solid var(--warning);
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  color: var(--fg-2);
}

/* ── Detail page (customer / vendor / product) ── */
.tv-detail-grid {
  display: grid;
  grid-template-columns: 320px 1fr;
  gap: 20px;
  align-items: start;
}
@media (max-width: 1024px) { .tv-detail-grid { grid-template-columns: 1fr; } }

.tv-detail-side { display: flex; flex-direction: column; gap: 16px; }
.tv-detail-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 24px 20px;
  gap: 10px;
}
.tv-detail-hero__avatar {
  width: 72px; height: 72px;
  border-radius: 50%;
  background: var(--primary-50);
  color: var(--primary);
  display: flex; align-items: center; justify-content: center;
  font-size: 28px;
  font-weight: 600;
  font-family: var(--font-num);
}
.tv-detail-hero__name { margin: 0; font-size: 16px; font-weight: 600; line-height: 1.3; }
.tv-detail-hero__meta { font-size: 12.5px; color: var(--fg-3); }

.tv-meta-list { display: flex; flex-direction: column; gap: 2px; }
.tv-meta-list__row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.tv-meta-list__row:last-child { border-bottom: none; }
.tv-meta-list__label { color: var(--fg-3); flex: none; }
.tv-meta-list__value { color: var(--fg-1); text-align: right; word-break: break-word; }

/* ── Phase 4: Segmented control ─── */
.tv-segmented {
  display: inline-flex;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 3px;
  gap: 2px;
}
.tv-segmented__btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--fg-3);
  border-radius: var(--radius-sm);
  transition: background 150ms, color 150ms, box-shadow 150ms;
}
.tv-segmented__btn:hover { color: var(--fg-1); }
.tv-segmented__btn.is-active {
  background: var(--card);
  color: var(--fg-1);
  box-shadow: var(--shadow-sm);
}
.tv-iconbtn--sm { width: 28px; height: 28px; }

/* ── Phase 4: Notifications Page ─── */
.tv-notif-page {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: 20px;
}
.tv-notif-page__side {
  display: flex; flex-direction: column;
  gap: 4px;
  position: sticky; top: 84px;
  align-self: flex-start;
}
.tv-notif-page__filter {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius);
  font-size: 13px;
  color: var(--fg-2);
  font-weight: 500;
  transition: background 150ms, color 150ms;
}
.tv-notif-page__filter:hover { background: var(--hover); color: var(--fg-1); }
.tv-notif-page__filter.is-active {
  background: var(--primary-50);
  color: var(--primary);
  font-weight: 600;
}
.tv-notif-page__filter span:first-of-type { flex: 1; text-align: left; }
.tv-notif-page__count {
  background: var(--primary);
  color: white;
  font-size: 10.5px;
  font-weight: 600;
  padding: 1px 6px;
  border-radius: 999px;
  min-width: 18px;
  text-align: center;
}
.tv-notif-page__legend {
  margin-top: 16px;
  padding: 12px;
  background: var(--bg);
  border-radius: var(--radius);
  border: 1px solid var(--border);
}
.tv-notif-page__legend-title {
  font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--fg-4);
  margin-bottom: 8px;
}
.tv-notif-page__legend-row {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 0;
  font-size: 12.5px;
  color: var(--fg-2);
}
.tv-notif-page__list { display: flex; flex-direction: column; gap: 16px; }
.tv-notif-page__group-head {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--fg-3);
  margin-bottom: 8px;
}
.tv-notif-page__item {
  display: flex; gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
  position: relative;
  transition: background 150ms;
}
.tv-notif-page__item:last-child { border-bottom: none; }
.tv-notif-page__item:hover { background: var(--hover); }
.tv-notif-page__item.is-unread { background: linear-gradient(90deg, var(--primary-50), transparent 50%); }
[data-theme="dark"] .tv-notif-page__item.is-unread { background: linear-gradient(90deg, rgba(79,70,229,0.15), transparent 50%); }
.tv-notif-page__body { flex: 1; min-width: 0; }
.tv-notif-page__title { font-size: 13.5px; font-weight: 500; color: var(--fg-1); }
.tv-notif-page__desc { font-size: 12.5px; color: var(--fg-3); margin-top: 3px; }
.tv-notif-page__meta {
  display: flex; align-items: center; gap: 4px;
  font-size: 11.5px; color: var(--fg-4);
  margin-top: 6px;
}
.tv-notif-page__actions {
  display: flex; gap: 4px;
  opacity: 0; transition: opacity 150ms;
  flex: none;
}
.tv-notif-page__item:hover .tv-notif-page__actions { opacity: 1; }
.tv-notif-page__dot {
  position: absolute; left: 6px; top: 50%; transform: translateY(-50%);
  width: 6px; height: 6px; background: var(--primary); border-radius: 50%;
}

/* ── Phase 4: Todos / Kanban / Calendar ─── */
.tv-todo-toolbar {
  display: flex; gap: 10px; align-items: center;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.tv-kanban {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}
.tv-kanban__col {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 12px;
  min-height: 360px;
}
.tv-kanban__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
.tv-kanban__head-left { display: flex; align-items: center; gap: 8px; }
.tv-kanban__dot { width: 8px; height: 8px; border-radius: 50%; }
.tv-kanban__label { font-size: 13px; font-weight: 600; }
.tv-kanban__count { background: var(--card); border: 1px solid var(--border); padding: 1px 8px; border-radius: 999px; font-size: 11.5px; color: var(--fg-3); font-weight: 500; }
.tv-kanban__list { display: flex; flex-direction: column; gap: 8px; }
.tv-kanban__empty { text-align: center; padding: 24px; font-size: 12px; color: var(--fg-4); border: 1px dashed var(--border); border-radius: var(--radius); }

.tv-todo-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px;
  cursor: grab;
  transition: transform 150ms, box-shadow 150ms, border-color 150ms;
}
.tv-todo-card:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); transform: translateY(-1px); }
.tv-todo-card:active { cursor: grabbing; }
.tv-todo-card__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.tv-todo-card__tag { font-size: 11px; color: var(--fg-3); }
.tv-todo-card__title { font-size: 13px; font-weight: 500; color: var(--fg-1); line-height: 1.4; }
.tv-todo-card__desc { font-size: 12px; color: var(--fg-3); margin-top: 4px; line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.tv-todo-card__link { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; color: var(--primary); margin-top: 8px; padding: 2px 6px; background: var(--primary-50); border-radius: 4px; }
.tv-todo-card__foot { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; }
.tv-todo-card__due { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; color: var(--fg-3); }
.tv-todo-card__due.is-today { color: var(--warning); font-weight: 600; }
.tv-todo-card__due.is-overdue { color: var(--danger); font-weight: 600; }

/* Calendar */
.tv-cal__head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
}
.tv-cal__title { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; }
.tv-cal {
  display: grid;
  /* minmax(0, 1fr), not 1fr. A bare `1fr` floors each column at its content's
     min-content width, and the task chips are `white-space: nowrap`, so a day
     holding "ติดตามใบเสนอราคา QT-2569-0042" forced its column wide and the grid
     overflowed its card: columns came out 173/201/222/163/203/154/**34**px, the
     Saturday column was squeezed to 34px, and the cell for the 1st — today —
     was pushed past the right edge of the viewport entirely. The ellipsis on
     .tv-cal__chip only takes effect once the column is allowed to be narrower
     than its text, which is what the 0 minimum here (and min-width on the cell)
     grants it. */
  grid-template-columns: repeat(7, minmax(0, 1fr));
  border-top: 1px solid var(--border);
}
.tv-cal__weekday {
  padding: 10px;
  text-align: center;
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--fg-3);
  background: var(--bg);
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.tv-cal__weekday:last-child { border-right: none; }
.tv-cal__cell {
  min-height: 100px;
  min-width: 0;              /* a grid item defaults to min-content; see .tv-cal */
  padding: 6px;
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 4px;
}
.tv-cal__cell:nth-child(7n+1) { border-left: none; }
.tv-cal__cell:nth-child(7n) { border-right: none; }
.tv-cal__cell.is-empty { background: var(--bg); }
.tv-cal__cell.is-today { background: var(--primary-50); }
.tv-cal__date {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--fg-2);
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
}
.tv-cal__cell.is-today .tv-cal__date {
  background: var(--primary);
  color: white;
  border-radius: 50%;
}
.tv-cal__items { display: flex; flex-direction: column; gap: 3px; }
.tv-cal__chip {
  font-size: 11px;
  padding: 2px 6px;
  border-radius: 4px;
  text-align: left;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-weight: 500;
}
.tv-cal__chip--danger { background: var(--danger-50); color: var(--danger); }
.tv-cal__chip--warning { background: var(--warning-50); color: var(--warning); }
.tv-cal__chip--neutral { background: var(--hover); color: var(--fg-2); }
.tv-cal__more { font-size: 11px; color: var(--fg-3); padding: 0 6px; }

/* ── Phase 4: Reports ─── */
.tv-reports-hero {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 24px;
  padding: 20px 24px;
  background: linear-gradient(135deg, var(--primary-50), transparent);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  margin-bottom: 20px;
}
[data-theme="dark"] .tv-reports-hero { background: linear-gradient(135deg, rgba(79,70,229,0.15), transparent); }
.tv-reports-pinned { display: grid; grid-template-columns: repeat(2, minmax(220px, 1fr)); gap: 8px; flex: 1; max-width: 720px; }
.tv-reports-pinned__item {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-align: left;
  transition: border-color 150ms, transform 150ms, box-shadow 150ms;
}
.tv-reports-pinned__item:hover { border-color: var(--primary); transform: translateY(-1px); box-shadow: var(--shadow-md); }
.tv-reports-pinned__bullet {
  width: 32px; height: 32px;
  border-radius: var(--radius);
  display: flex; align-items: center; justify-content: center;
  color: white;
  flex: none;
}
.tv-reports-pinned__title { font-size: 13px; font-weight: 600; color: var(--fg-1); }
.tv-reports-pinned__desc { font-size: 11.5px; color: var(--fg-3); margin-top: 2px; }
.tv-reports-groups { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
.tv-reports-group__head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.tv-reports-group__icon { width: 32px; height: 32px; border-radius: var(--radius); display: flex; align-items: center; justify-content: center; flex: none; }
.tv-reports-group__count { margin-left: auto; font-size: 11.5px; color: var(--fg-3); }
.tv-reports-group__list { display: flex; flex-direction: column; gap: 6px; }

.tv-report-card {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px;
  border-radius: var(--radius);
  text-align: left;
  transition: background 150ms;
  border: 1px solid transparent;
}
.tv-report-card:hover { background: var(--hover); border-color: var(--border); }
.tv-report-card__bullet { width: 6px; height: 36px; border-radius: 3px; flex: none; }
.tv-report-card__body { flex: 1; min-width: 0; }
.tv-report-card__title { font-size: 13px; font-weight: 500; color: var(--fg-1); }
.tv-report-card__desc { font-size: 11.5px; color: var(--fg-3); margin-top: 2px; }
.tv-report-card__arrow { color: var(--fg-4); transition: transform 150ms, color 150ms; flex: none; }
.tv-report-card:hover .tv-report-card__arrow { color: var(--primary); transform: translate(2px, -2px); }

.tv-report-filters {
  display: grid;
  grid-template-columns: repeat(4, 1fr) auto;
  gap: 12px;
  align-items: end;
}
.tv-report-kpis {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin-bottom: 16px;
}

@media (max-width: 1280px) {
  .tv-notif-page { grid-template-columns: 1fr; }
  .tv-notif-page__side { position: static; flex-direction: row; flex-wrap: wrap; }
  .tv-reports-groups { grid-template-columns: 1fr; }
  .tv-reports-pinned { grid-template-columns: 1fr; }
  .tv-kanban { grid-template-columns: 1fr; }
  .tv-report-filters { grid-template-columns: repeat(2, 1fr); }
}

/* ── Phase 5: Permissions Matrix ─── */
.tv-perm { display: grid; grid-template-columns: 220px 1fr; min-height: 480px; }
.tv-perm__sidebar { padding: 16px 12px; border-right: 1px solid var(--border); display: flex; flex-direction: column; gap: 4px; background: var(--bg); }
.tv-perm__role { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: var(--radius); transition: background 150ms; }
.tv-perm__role:hover { background: var(--hover); }
.tv-perm__role.is-active { background: var(--card); box-shadow: var(--shadow-sm); border: 1px solid var(--border); }
.tv-perm__main { padding: 20px 24px; }
.tv-perm__table { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.tv-perm__header, .tv-perm__row { display: grid; grid-template-columns: 2fr repeat(4, 1fr); align-items: center; }
.tv-perm__header { background: var(--bg); padding: 10px 16px; font-size: 11.5px; font-weight: 600; color: var(--fg-3); text-transform: uppercase; letter-spacing: 0.05em; }
.tv-perm__header > div:not(:first-child) { text-align: center; }
.tv-perm__row { padding: 10px 16px; border-top: 1px solid var(--border); }
.tv-perm__module { font-size: 13px; font-weight: 500; }
.tv-perm__cell { display: flex; justify-content: center; }
.tv-perm__check { width: 28px; height: 28px; border-radius: 6px; display: flex; align-items: center; justify-content: center; background: var(--bg); color: var(--fg-4); transition: all 150ms; border: 1px solid var(--border); }
.tv-perm__check.is-on { background: var(--success); color: white; border-color: var(--success); }
.tv-perm__check:hover:not(:disabled) { transform: scale(1.05); }
.tv-perm__check:disabled { opacity: 0.6; cursor: not-allowed; }

/* ── Phase 5: Settings ─── */
.tv-settings { display: grid; grid-template-columns: 240px 1fr; gap: 20px; }
.tv-settings__nav { display: flex; flex-direction: column; gap: 2px; position: sticky; top: 84px; align-self: flex-start; }
.tv-settings__navitem { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-radius: var(--radius); font-size: 13px; color: var(--fg-2); transition: background 150ms, color 150ms; }
.tv-settings__navitem:hover { background: var(--hover); }
.tv-settings__navitem.is-active { background: var(--primary-50); color: var(--primary); font-weight: 600; }
.tv-settings__main { display: flex; flex-direction: column; gap: 16px; }

/* Seven columns of controls do not fit a narrow settings pane, and the widest
   label ("หนังสือรับรองหัก ณ ที่จ่าย") was wrapping to three lines while the
   sample column ran off the edge. Fixed minimums plus a scroller of its own —
   the page body must never scroll sideways. */
.tv-numbering { overflow-x: auto; }
.tv-numbering__head, .tv-numbering__row {
  display: grid;
  grid-template-columns: minmax(150px, 1.6fr) minmax(90px, 1fr) minmax(110px, 1fr) minmax(100px, 1fr) minmax(70px, 0.7fr) minmax(90px, 1fr) minmax(130px, 1.3fr);
  gap: 10px; align-items: center;
  min-width: 780px;
}
.tv-numbering__head { padding: 8px 0; font-size: 11.5px; font-weight: 600; color: var(--fg-3); border-bottom: 1px solid var(--border); }
.tv-numbering__row { padding: 10px 0; border-bottom: 1px solid var(--border); }
.tv-numbering__row:last-child { border-bottom: none; }
.tv-numbering__sample { font-family: monospace; font-size: 12px; padding: 6px 10px; background: var(--bg); border-radius: 6px; border: 1px solid var(--border); }


/* ── Phase 5: Audit ─── */
.tv-audit { display: flex; flex-direction: column; }
.tv-audit__row { display: flex; gap: 14px; padding: 14px 20px; border-bottom: 1px solid var(--border); align-items: flex-start; }
.tv-audit__row:hover { background: var(--hover); }
.tv-audit__row:last-child { border-bottom: none; }
.tv-audit__icon { width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex: none; margin-top: 2px; }
.tv-audit__body { flex: 1; min-width: 0; }
.tv-audit__head { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; font-size: 13px; }
.tv-audit__user { font-weight: 600; color: var(--fg-1); }
.tv-audit__action { font-weight: 500; }
.tv-audit__module { color: var(--fg-3); font-size: 12.5px; }
.tv-audit__target { background: var(--bg); border: 1px solid var(--border); padding: 1px 8px; border-radius: 4px; font-family: monospace; font-size: 11.5px; }
.tv-audit__desc { font-size: 12.5px; color: var(--fg-3); margin-top: 4px; line-height: 1.5; }
.tv-audit__meta { text-align: right; flex: none; font-size: 11.5px; color: var(--fg-4); }
.tv-audit__time { font-family: monospace; font-size: 12.5px; color: var(--fg-2); font-weight: 500; }
.tv-audit__date { margin-top: 2px; }
.tv-audit__ip { margin-top: 4px; font-family: monospace; opacity: 0.7; }

/* ── Phase 5: Profile ─── */
.tv-profile { max-width: 920px; }
.tv-profile__hero { display: flex; align-items: center; gap: 20px; padding: 24px; }
.tv-profile__avatar { width: 80px; height: 80px; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-size: 30px; font-weight: 700; flex: none; }
.tv-pwd-strength { padding: 14px; background: var(--bg); border-radius: var(--radius); border: 1px solid var(--border); }
.tv-session { display: flex; gap: 14px; padding: 16px 20px; border-bottom: 1px solid var(--border); align-items: center; }
.tv-session:last-child { border-bottom: none; }
.tv-session__icon { width: 44px; height: 44px; border-radius: 10px; background: var(--primary-50); color: var(--primary); display: flex; align-items: center; justify-content: center; flex: none; }

/* ── Phase 5: Error pages ─── */
.tv-errpage { display: flex; align-items: center; justify-content: center; min-height: 70vh; padding: 40px 20px; }
.tv-errpage__inner { max-width: 480px; text-align: center; }
.tv-errpage__visual { position: relative; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 24px; }
.tv-errpage__code { font-size: 120px; font-weight: 800; line-height: 1; letter-spacing: -0.05em; opacity: 0.2; }
.tv-errpage__icon { position: absolute; width: 96px; height: 96px; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
.tv-errpage__title { font-size: 24px; font-weight: 700; margin: 0 0 12px; }
.tv-errpage__message { font-size: 14px; color: var(--fg-3); line-height: 1.6; margin: 0 0 28px; }
.tv-errpage__actions { display: flex; gap: 10px; justify-content: center; }
.tv-errpage__details { margin-top: 24px; padding: 12px; background: var(--bg); border-radius: 8px; color: var(--fg-4); }

@media (max-width: 1024px) {
  /* minmax(0, 1fr) rather than 1fr: the nav rail becomes a horizontal row here
     and its min-content is the full width of all six items (~800px), which a
     bare fr track would refuse to shrink below — so the whole settings grid
     stayed wider than the phone screen and spilled past the right edge. */
  .tv-perm { grid-template-columns: minmax(0, 1fr); }
  .tv-perm__sidebar { flex-direction: row; flex-wrap: wrap; border-right: none; border-bottom: 1px solid var(--border); }
  .tv-settings { grid-template-columns: minmax(0, 1fr); }
  .tv-settings__nav { position: static; flex-direction: row; flex-wrap: wrap; }
  .tv-numbering__head { display: none; }
  .tv-numbering__row { grid-template-columns: 1fr 1fr; }
}

/* ── Product card / grid ── */
.tv-prod-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
}
.tv-prod-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  transition: border-color 150ms, transform 150ms;
  cursor: pointer;
}
.tv-prod-card:hover { border-color: var(--primary); transform: translateY(-2px); }
.tv-prod-card__cover {
  background: linear-gradient(135deg, var(--bg), var(--hover));
  border-radius: var(--radius);
  height: 100px;
  display: flex; align-items: center; justify-content: center;
  color: var(--fg-4);
  border: 1px solid var(--border);
}
.tv-prod-card__sku { font-size: 11px; color: var(--fg-3); font-family: var(--font-num); letter-spacing: 0.04em; }
.tv-prod-card__name { font-size: 13.5px; font-weight: 600; line-height: 1.4; min-height: 38px; }
.tv-prod-card__row { display: flex; justify-content: space-between; align-items: center; }
.tv-prod-card__price { font-size: 16px; font-weight: 600; font-family: var(--font-num); }

/* ── Quotation editor ── */
.tv-doc-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.tv-doc-grid {
  display: grid;
  grid-template-columns: 2fr repeat(4, minmax(150px, 1fr));
  gap: 12px;
  align-items: end;
}
@media (max-width: 1280px) {
  .tv-doc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .tv-doc-grid { grid-template-columns: 1fr; }
}
.tv-doc-editor {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 20px;
  align-items: start;
}
@media (max-width: 1280px) { .tv-doc-editor { grid-template-columns: 1fr; } }

.tv-line-table {
  width: 100%;
  font-size: 13px;
}
.tv-line-table__head,
.tv-line-table__row {
  display: grid;
  grid-template-columns: 34px minmax(220px, 1fr) 120px 150px 110px 130px 34px;
  gap: 8px;
  align-items: center;
}
/* Quotation lines: no per-line ส่วนลด column — this document discounts once,
   at the bottom of the bill. */
.tv-line-table--nodisc .tv-line-table__head,
.tv-line-table--nodisc .tv-line-table__row {
  grid-template-columns: 34px minmax(220px, 1fr) 120px 150px 130px 34px;
}
/* งวดการชำระเงิน: description, percentage, derived amount. */
.tv-line-table--plan .tv-line-table__head,
.tv-line-table--plan .tv-line-table__row {
  grid-template-columns: 34px minmax(220px, 1fr) 130px 150px 34px;
}
.tv-line-table__head {
  padding: 10px 8px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  color: var(--fg-3);
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
}
.tv-line-table__row {
  padding: 8px;
  border-bottom: 1px solid var(--border);
}
.tv-line-table__row:last-child { border-bottom: 0; }
.tv-line-table__num { color: var(--fg-3); font-variant-numeric: tabular-nums; }
.tv-line-table__total { text-align: right; font-weight: 600; }
@media (max-width: 1100px) {
  .tv-line-table { overflow-x: auto; }
  .tv-line-table__head,
  .tv-line-table__row { min-width: 820px; }
}
.tv-line-table thead th {
  text-align: left;
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--fg-3);
  padding: 10px 8px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}
.tv-line-table tbody td {
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.tv-line-table tbody tr:last-child td { border-bottom: none; }
.tv-line-table .tv-line-input {
  width: 100%;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 6px 8px;
  font: inherit;
  color: inherit;
  outline: none;
  transition: border-color 150ms, background 150ms;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.tv-line-table .tv-line-input--text { text-align: left; }
.tv-line-table .tv-line-input:hover { background: var(--hover); }
.tv-line-table .tv-line-input:focus { border-color: var(--primary); background: var(--card); }
.tv-line-table .tv-line-drag {
  width: 24px; height: 24px;
  display: flex; align-items: center; justify-content: center;
  color: var(--fg-4);
  cursor: grab;
}
.tv-line-table .tv-line-del {
  width: 26px; height: 26px;
  border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center;
  color: var(--fg-3);
  transition: all 150ms;
}
.tv-line-table .tv-line-del:hover { background: var(--danger-50); color: var(--danger); }

.tv-textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  color: var(--fg-1);
  font-size: 13px;
  line-height: 1.5;
  resize: vertical;
  outline: none;
}
.tv-textarea:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-50);
}

.tv-totals { display: flex; flex-direction: column; gap: 10px; padding: 18px; }
.tv-totals__row { display: flex; justify-content: space-between; font-size: 13px; }
.tv-totals__row--grand {
  padding-top: 12px;
  border-top: 1px solid var(--border);
  margin-top: 4px;
  font-size: 16px;
  font-weight: 600;
}
.tv-totals__row--grand .tv-totals__value { color: var(--primary); font-size: 20px; font-family: var(--font-num); }
.tv-totals__label { color: var(--fg-3); }
.tv-totals__value { font-family: var(--font-num); font-variant-numeric: tabular-nums; }

/* ── Quotation document (.tv-pdf-paper) ──
   Colours are fixed rather than themed: this markup is snapshotted by
   html2canvas for the PDF and printed on white paper either way. */
.tv-pdf-stage { display: flex; flex-direction: column; gap: 16px; }
.tv-pdf-toolbar { display: flex; align-items: center; gap: 8px; }
/* ── Document palette ────────────────
   Brand accent for printed documents. Declared here, on the document elements
   themselves, and deliberately NOT reusing the app's --primary/--fg-* tokens:
   those flip under [data-theme="dark"], and a document is printed on white
   paper and snapshotted for the PDF, so it must look identical in both themes.
   These names must never be redefined under a theme selector.

   Restraint is the point — the accent carries the title, the rules and the
   table head; everything a person has to read stays near-black on white. */
.tv-pdf-paper,
.tv-pdf-frame {
  --doc-accent: #E87E47;   /* brand orange */
  --doc-ink:    #B35A28;   /* darker accent — accessible for text on white */
  --doc-tint:   #FDF4EE;   /* wash for table heads and the customer box */
  --doc-edge:   #F1D6C2;   /* border tint that belongs to the wash */
  --doc-line:   #e5e7eb;   /* neutral hairline, unchanged */
}

.tv-pdf-paper {
  position: relative;
  background: white;
  color: #1a1a1a;
  /* Real A4 so the preview matches the exported page 1:1 */
  width: 210mm;
  min-height: 297mm;
  max-width: 100%;
  margin: 0 auto;
  padding: 18mm 16mm;
  font-size: 12px;
  line-height: 1.55;
  font-family: var(--font-sans);
  border: 1px solid #e5e7eb;
  border-radius: 4px;
  box-shadow: var(--shadow-md);
  /* A column so the signature block can be pushed to the foot of the page with
     margin-top:auto. Children never shrink — on a full page the content must
     push the paper taller and paginate, not compress into it. */
  display: flex;
  flex-direction: column;
}
.tv-pdf-paper > * { flex: 0 0 auto; }
.tv-pdf-stamp {
  position: absolute; top: 28px; right: 44px;
  border: 1.5px solid var(--doc-accent); color: var(--doc-accent);
  padding: 3px 12px; border-radius: 4px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.06em;
  transform: rotate(-8deg);
}
.tv-pdf-head {
  display: flex; justify-content: space-between; gap: 24px;
  margin-bottom: 20px; padding-bottom: 14px;
  border-bottom: 2px solid var(--doc-accent);
}
.tv-pdf-logo { display: flex; gap: 12px; align-items: flex-start; margin-bottom: 10px; }
/* Width only, never object-fit: html2canvas ignores object-fit and crops the
   logo when exporting, so the aspect ratio has to come from the image itself. */
.tv-pdf-logo img { width: 32px; height: auto; flex: none; }
.tv-pdf-logo img.tv-pdf-logo__img--custom { width: auto; max-width: 150px; max-height: 46px; }
.tv-pdf-companyname { font-size: 14px; font-weight: 700; }
.tv-pdf-companysub { font-size: 11px; color: #6B7280; }
.tv-pdf-addr { font-size: 10.5px; color: #555; line-height: 1.5; max-width: 320px; }
.tv-pdf-doctitle { text-align: right; flex: none; }
.tv-pdf-doctitle__th { font-size: 22px; font-weight: 700; line-height: 1.2; color: var(--doc-accent); }
.tv-pdf-doctitle__en { font-size: 12px; color: #6B7280; margin-bottom: 10px; }
.tv-pdf-meta { font-size: 11px; line-height: 1.7; }
.tv-pdf-meta span { color: #6B7280; margin-right: 4px; }
.tv-pdf-customer {
  background: var(--doc-tint); border: 1px solid var(--doc-edge); border-radius: 4px;
  padding: 12px 14px; margin-bottom: 18px;
}
.tv-pdf-customer__label {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em;
  color: #6B7280; margin-bottom: 4px;
}
.tv-pdf-customer__name { font-size: 13.5px; font-weight: 600; }
.tv-pdf-customer__addr { font-size: 10.5px; color: #555; line-height: 1.5; margin-top: 3px; }
.tv-pdf-table { width: 100%; border-collapse: collapse; margin-bottom: 16px; }
.tv-pdf-table th, .tv-pdf-table td {
  padding: 8px 10px; border-bottom: 1px solid #e5e7eb;
  font-size: 11.5px; vertical-align: top;
}
.tv-pdf-table th {
  background: var(--doc-tint); font-weight: 600; text-align: left;
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--doc-ink);
  border-bottom: 1.5px solid var(--doc-accent);
}
.tv-pdf-table td.tv-num, .tv-pdf-table th.tv-num { text-align: right; }
.tv-pdf-totals { margin-left: auto; width: 280px; }
.tv-pdf-totals > div { display: flex; justify-content: space-between; padding: 4px 0; font-size: 11.5px; }
.tv-pdf-totals__grand {
  border-top: 2px solid var(--doc-accent); margin-top: 4px; padding-top: 8px !important;
  font-weight: 700; font-size: 13.5px;
}
.tv-pdf-notes { margin-top: 18px; font-size: 11px; line-height: 1.6; }
.tv-pdf-notes__label {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em;
  color: #6B7280; margin-bottom: 3px;
}
.tv-pdf-footer {
  margin-top: 14px; padding: 8px 12px; background: var(--doc-tint);
  border-radius: 4px; font-size: 11px;
}
/* ชื่องาน — the job this quotation is for, between the customer block and the
   items. One line, so it reads as a heading for the table under it. */
.tv-pdf-jobtitle {
  display: flex; align-items: baseline; gap: 10px;
  margin-bottom: 14px; padding-bottom: 8px;
  border-bottom: 1px solid #e5e7eb;
}
.tv-pdf-jobtitle__label {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em;
  color: #6B7280; flex: none;
}
.tv-pdf-jobtitle__value { font-size: 12.5px; font-weight: 600; }
/* ยอดสุทธิ spans the full width so the amount in words can sit flush left on
   the same line as the figure. */
.tv-pdf-grand {
  display: flex; align-items: baseline; gap: 12px;
  border-top: 2px solid var(--doc-accent);
  margin-top: 4px; padding-top: 8px;
  font-weight: 700; font-size: 13.5px;
}
.tv-pdf-grand__words {
  flex: 1; font-size: 11.5px; font-weight: 500; color: #374151;
}
.tv-pdf-grand__label { flex: none; }
.tv-pdf-grand__amount { flex: none; min-width: 120px; text-align: right; color: var(--doc-ink); }
.tv-pdf-plan { margin-top: 14px; }
.tv-pdf-plan .tv-pdf-table { margin-top: 5px; margin-bottom: 0; }
/* The instalment rows are a summary, not the document's substance — set tighter
   than the item table so a quotation with a plan still fits one A4 page. */
.tv-pdf-table--plan th, .tv-pdf-table--plan td { padding: 5px 10px; }
/* Signatures sit at the foot of the page whatever the document's length, with
   the ตราประทับ between the two blocks. */
.tv-pdf-sign {
  position: relative;
  /* The middle column is a fixed reservation, not `auto`: the seal inside it is
     positioned out of flow, so `auto` would collapse to zero and the stamp
     would print across the ผู้อนุมัติ block. */
  display: grid; grid-template-columns: 1fr 118px 1fr; gap: 16px;
  align-items: end; margin-top: auto; padding-top: 14px;
}
/* Placed explicitly. The seal between them is out of flow and so claims no grid
   cell — left to auto-placement, ผู้อนุมัติ lands in the middle column and the
   stamp prints on top of it. */
.tv-pdf-sign__col { text-align: center; font-size: 11px; }
.tv-pdf-sign__col:first-child { grid-column: 1; }
.tv-pdf-sign__col:last-child { grid-column: 3; }
/* Company names are long. Two lines here would push the signatures — and with
   them an exactly-A4 document — onto a second page, so the line is set smaller
   and given a fixed height that fits the two-line worst case either way. */
.tv-pdf-sign__inname {
  font-size: 10.5px; line-height: 1.35; color: #374151; margin-bottom: 4px;
  height: 29px; display: flex; align-items: flex-end; justify-content: center;
}
/* A fixed-height slot so both columns keep the same baseline whether or not a
   signature image is set. */
.tv-pdf-sign__ink { height: 44px; display: flex; align-items: flex-end; justify-content: center; }
/* max-* only, both dimensions auto: the image keeps its own aspect ratio.
   Never object-fit — html2canvas ignores it and crops the exported file. */
.tv-pdf-sign__ink img { max-height: 44px; max-width: 190px; }
.tv-pdf-sign__line { border-top: 1px solid #1a1a1a; margin-bottom: 6px; }
/* Out of flow on purpose. A 3cm stamp is taller than a signature column, and in
   normal flow it would drive the height of the whole block — enough to push an
   otherwise exactly-A4 document onto a second exported page. Centred with auto
   margins rather than a transform, which html2canvas renders more predictably. */
.tv-pdf-sign__seal {
  position: absolute; left: 0; right: 0; bottom: 14px; margin: 0 auto;
  width: 118px; display: flex; align-items: flex-end; justify-content: center;
}
.tv-pdf-sign__seal img { max-width: 118px; max-height: 118px; }

/* ── PDF preview ── */
.tv-pdf-frame {
  background: white;
  color: #1a1a1a;
  /* Real A4 so the preview matches the exported page 1:1 */
  width: 210mm;
  min-height: 297mm;
  max-width: 100%;
  margin: 0 auto;
  padding: 18mm 16mm;
  font-size: 12px;
  line-height: 1.5;
  font-family: var(--font-sans);
  border: 1px solid #e5e7eb;
  border-radius: 4px;
  box-shadow: var(--shadow-md);
}
.tv-pdf-frame h1 { margin: 0 0 4px; font-size: 22px; font-weight: 600; color: var(--doc-accent); }
.tv-pdf-frame__head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  border-bottom: 2px solid var(--doc-accent);
  padding-bottom: 16px;
  margin-bottom: 16px;
}
.tv-pdf-frame__co { display: flex; gap: 12px; align-items: flex-start; }
/* see .tv-pdf-logo img — object-fit is not honoured by the PDF exporter */
.tv-pdf-frame__co img { width: 32px; height: auto; flex: none; }
.tv-pdf-frame__co-name { font-size: 13.5px; font-weight: 600; }
.tv-pdf-frame__co-meta { font-size: 10.5px; color: #555; line-height: 1.45; }
/* min-width keeps the Thai document title on one line instead of breaking
   between "ณ ที่" and "จ่าย" */
.tv-pdf-frame__title-block { text-align: right; min-width: 290px; flex: none; }
.tv-pdf-frame__copy {
  font-size: 11px; font-weight: 500; color: var(--doc-accent);
  border: 1px solid var(--doc-accent); padding: 2px 10px; border-radius: 999px;
  display: inline-block; margin-top: 4px;
}
.tv-pdf-frame__grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-bottom: 16px;
}
.tv-pdf-frame__grid h4 { margin: 0 0 6px; font-size: 11px; font-weight: 600; text-transform: uppercase; color: var(--doc-ink); letter-spacing: 0.04em; }
.tv-pdf-frame__grid p { margin: 0; font-size: 11.5px; line-height: 1.5; }
.tv-pdf-frame table { width: 100%; border-collapse: collapse; margin-bottom: 12px; }
.tv-pdf-frame th, .tv-pdf-frame td { padding: 8px 10px; border-bottom: 1px solid #e5e7eb; font-size: 11.5px; vertical-align: top; }
.tv-pdf-frame th {
  background: var(--doc-tint); font-weight: 600; text-align: left; font-size: 10.5px;
  text-transform: uppercase; color: var(--doc-ink); border-bottom: 1.5px solid var(--doc-accent);
}
.tv-pdf-frame td.tv-num, .tv-pdf-frame th.tv-num { text-align: right; }
.tv-pdf-frame__totals { display: flex; justify-content: flex-end; }
.tv-pdf-frame__totals-box { min-width: 280px; }
.tv-pdf-frame__totals-row { display: flex; justify-content: space-between; padding: 4px 0; font-size: 11.5px; }
.tv-pdf-frame__totals-row--grand { border-top: 2px solid var(--doc-accent); margin-top: 4px; padding-top: 8px; font-weight: 700; font-size: 13px; }
.tv-pdf-frame__amount-text { margin: 12px 0; padding: 8px 12px; background: var(--doc-tint); border-radius: 4px; font-size: 11px; }
.tv-pdf-frame__sigs { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-top: 32px; padding-top: 24px; }
.tv-pdf-frame__sig-line { border-top: 1px solid #1a1a1a; margin-top: 36px; padding-top: 6px; text-align: center; font-size: 10.5px; color: #6B7280; }

.tv-page { animation: tv-page-in 200ms ease-out; }
@keyframes tv-page-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (max-width: 1280px) {
  .tv-grid-kpi { grid-template-columns: repeat(2, 1fr); }
  .tv-dash-grid { grid-template-columns: 1fr; }
}
@media (max-width: 1024px) {
  :root { --sidebar-w: 200px; }
  .tv-userbtn__meta { display: none; }
}



  /* Page enter transition */
  .tv-page-anim { animation: tv-page-in 200ms ease-out; }
  @keyframes tv-page-in {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
  }
  /* Recharts dark mode tweaks */
  [data-theme="dark"] .recharts-cartesian-grid line { stroke: #334155 !important; }

/* ── Data source banner + boot screen (phase 2) ───────────────────── */
.tv-databanner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 14px;
  margin-bottom: 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--warning-50);
  color: var(--fg-2);
  font-size: 12.5px;
}
.tv-databanner.is-error {
  background: var(--danger-50);
  border-color: var(--danger);
}
.tv-databanner strong { color: var(--fg-1); font-weight: 600; }
.tv-databanner .tv-link { flex: none; font-size: 12.5px; }

@keyframes tv-boot-slide {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(350%); }
}
.tv-boot-bar { animation: tv-boot-slide 1100ms ease-in-out infinite; }

/* Supabase connection card */
.tv-conn-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  font-size: 12.5px;
}
.tv-conn-counts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 6px;
  margin-top: 12px;
}
.tv-conn-counts div {
  display: flex;
  justify-content: space-between;
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 12px;
  color: var(--fg-2);
}

/* ── Phones and narrow windows ───────
   The shell is a two-column grid that always reserved --sidebar-w, so at 375px
   the sidebar alone was wider than the screen and pushed the whole app off to
   the right: every page scrolled horizontally and the KPI figures were cut in
   half. Below this breakpoint the sidebar stops being a column and becomes an
   overlay drawer, and `is-collapsed` means "off-canvas" rather than "narrow".
   AppShell starts collapsed at this width and re-collapses after navigating. */
@media (max-width: 900px) {
  .tv-app,
  .tv-app.is-collapsed {
    /* minmax(0, 1fr): a bare 1fr keeps a min-content floor, and the topbar's
       min-content is the sum of its buttons (~328px). On a 320px phone that
       made the whole shell — topbar, main and scrim — 8px wider than the
       screen, so every page carried a permanent sideways wobble. */
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "topbar" "main";
  }

  .tv-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 60;
    width: min(80vw, var(--sidebar-w));
    height: 100dvh;            /* dvh, so mobile browser chrome cannot clip the last item */
    box-shadow: var(--shadow-lg);
    transition: transform 250ms ease;
  }
  /* Never the icons-only rail on a phone: at this width the drawer is either
     fully open or fully out of the way. */
  .tv-app.is-collapsed .tv-sidebar { transform: translateX(-100%); }
  .tv-app:not(.is-collapsed) .tv-sidebar { transform: translateX(0); }
  .tv-app.is-collapsed .tv-sidebar .tv-nav__label,
  .tv-app.is-collapsed .tv-sidebar .tv-navgroup__title,
  .tv-app.is-collapsed .tv-sidebar .tv-sidebar__brand-text { display: revert; }

  .tv-sidebar-scrim {
    position: fixed;
    inset: 0;
    z-index: 55;
    background: rgba(15, 23, 42, 0.45);
    opacity: 1;
    transition: opacity 250ms ease;
  }
  .tv-app.is-collapsed .tv-sidebar-scrim { opacity: 0; pointer-events: none; }

  .tv-main { padding: 16px 14px 40px; }
  .tv-topbar { padding: 0 12px; }
  .tv-topbar__menu { display: flex; }
  /* The search box is the widest thing in the bar and the first to push the
     rest off the edge. It collapses to its icon; the full search is still one
     tap away on the same button, and on ⌘K with a keyboard attached. */
  .tv-search { min-width: 0; padding: 0 10px; }
  .tv-search__placeholder,
  .tv-search .tv-kbd { display: none; }

  /* Same idea for the two widest controls on the right: the create button keeps
     its icon, and the account button drops the email beside the avatar. */
  .tv-topbar__right .tv-btn--primary .tv-btn__label,
  .tv-topbar__right .tv-btn--primary > span:not(.tv-avatar),
  .tv-userbtn__meta,
  .tv-userbtn__name,
  .tv-userbtn__role { display: none; }
  .tv-topbar__right { gap: 4px; min-width: 0; }
  .tv-topbar__left { min-width: 0; flex: 1; }
  .tv-topbar { gap: 8px; }
  /* Menus anchored to the right edge must open inside the screen, not past it. */
  .tv-dropdown__menu { max-width: calc(100vw - 20px); }

  /* Multi-column page furniture collapses to one column rather than overflowing.
     minmax(0, 1fr), never a bare 1fr: a bare fr keeps a min-content floor, and
     any of these cards holding a table then stays as wide as the table instead
     of collapsing — which is how the dashboard's เอกสารล่าสุด card ended up
     510px wide inside a 347px page. */
  .tv-grid-kpi,
  .tv-dash-grid,
  .tv-reports-groups,
  .tv-report-filters,
  .tv-detail-grid,
  .tv-payvoucher-groups { grid-template-columns: minmax(0, 1fr); }

  /* Two across for the small stat tiles — four of them stacked one per row
     pushed the actual table three screens down on every list page. */
  .tv-summary-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .tv-summary-tile { padding: 10px 12px; }
  .tv-summary-tile__value { font-size: 17px; }

  /* The flex row is .tv-pagehead__row — .tv-pagehead is the plain block that
     wraps the breadcrumbs above it, so setting flex-direction there did
     nothing and the header never actually stacked: the title and its
     description stayed crushed into a narrow left column with the action
     buttons alongside them. */
  .tv-pagehead__row { flex-direction: column; align-items: stretch; gap: 12px; }
  .tv-pagehead__title { font-size: 19px; }
  .tv-pagehead__actions { width: 100%; flex-wrap: wrap; }
  /* Full-width action buttons, so a two-button header reads as two rows of
     real tap targets rather than two chips floating at one edge. */
  .tv-pagehead__actions > * { flex: 1 1 auto; justify-content: center; }

  /* Tab rails scroll sideways instead of squeezing. Five tabs sharing 313px
     wrapped "ข้อมูลทั่วไป" onto two lines, "โลโก้และลายเซ็น" onto three, and
     pushed ธนาคาร clean off the screen — a tab nothing could tap. Each item
     keeps its natural width and the rail scrolls. */
  .tv-tabs, .tv-settings__nav {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .tv-tabs::-webkit-scrollbar, .tv-settings__nav::-webkit-scrollbar { display: none; }
  .tv-tabs__item, .tv-tab, .tv-settings__navitem { flex: 0 0 auto; white-space: nowrap; }

  /* Avatar, name and the ออกจากระบบ button do not fit on one line at 375px —
     the button was landing past the right edge. */
  .tv-profile__hero { flex-wrap: wrap; gap: 14px; padding: 18px; }
  .tv-profile__avatar { width: 56px; height: 56px; font-size: 22px; }

  /* Drawers and modals take the full width instead of a fixed one. */
  .tv-drawer { width: 100vw !important; max-width: 100vw; }
  .tv-modal { width: calc(100vw - 24px); max-width: calc(100vw - 24px); }
}

/* The scrim only exists as an overlay on small screens. */
@media (min-width: 901px) {
  .tv-sidebar-scrim { display: none; }
}

/* Line-item description — the sentence under the product name.
   In the printed document it must stay a fixed light colour like everything
   else inside .tv-pdf-paper / .tv-pdf-frame: the document is printed on white
   paper and snapshotted for the PDF either way, so it must not follow dark mode. */
.tv-pdf-linedesc {
  /* Deliberately tight. The A4 body is 1122.5px at 96dpi and a loaded document
     already fills it, so every pixel here is one the signature block loses —
     four two-line descriptions at 10px/1.45 pushed the page over by 136px and
     spilled a second sheet. At these values the same document lands back
     inside one page; genuinely long text still flows to page 2, which
     downloadElementPdf paginates cleanly. */
  margin-top: 2px;
  font-size: 9px;
  line-height: 1.3;
  color: #666;
  white-space: pre-wrap;
}
/* In the editor the description sits under the product picker and stays small,
   so a long paragraph cannot push the line row out of alignment. */
.tv-line-table__desc {
  margin-top: 6px;
  font-size: 12px;
  min-height: 0;
  resize: vertical;
}

/* The description row sits directly under its item and carries no top border,
   so the two read as one entry rather than two. */
.tv-pdf-paper tr.tv-pdf-row--hasdesc > td,
.tv-pdf-frame tr.tv-pdf-row--hasdesc > td { border-bottom: none; padding-bottom: 1px; }
/* The description row is part of the entry above it, not a row of its own, so
   it keeps only the bottom padding that separates one entry from the next.
   Each of these rows costs page height the signature block needs. */
.tv-pdf-paper tr.tv-pdf-descrow > td,
.tv-pdf-frame tr.tv-pdf-descrow > td { padding-top: 0; padding-bottom: 5px; }

/* ── Paged documents ─────────────────
   Each page is a real A4 sheet, not a slice of one long one. PagedPaper
   measures the rows and fills pages so nothing has to be cut at a boundary,
   which is what lets every page carry its own letterhead and signature. */
.tv-pdf-pages { display: flex; flex-direction: column; align-items: center; gap: 20px; }

/* Exactly A4 — height AND width, never `max-width: 100%`. The content was
   measured against this box; a page that reflows to the screen is a different
   document from the one that gets exported. A narrow screen scales the whole
   sheet down instead (--tv-page-scale), the way a PDF viewer zooms out. */
.tv-pdf-paper.tv-pdf-page,
.tv-pdf-frame.tv-pdf-page {
  width: 210mm;
  max-width: none;
  height: 297mm;
  min-height: 297mm;
  overflow: hidden;
  transform: scale(var(--tv-page-scale, 1));
  transform-origin: top left;
}
/* Holds the space the scaled page actually occupies, so the pages stack
   correctly instead of overlapping. */
.tv-pdf-pageslot {
  width: calc(210mm * var(--tv-page-scale, 1));
  height: calc(297mm * var(--tv-page-scale, 1));
  flex: 0 0 auto;
}

/* The signature block plus the page number, pinned to the foot of every page. */
.tv-pdf-pagefoot { margin-top: auto; }
.tv-pdf-pagefoot .tv-pdf-sign { margin-top: 0; }
.tv-pdf-pageno {
  margin-top: 6px;
  padding-top: 5px;
  border-top: 1px solid #e5e7eb;
  text-align: center;
  font-size: 9.5px;
  color: #94a3b8;
}

/* The stamp is absolutely positioned inside the page it belongs to. */
.tv-pdf-page .tv-pdf-stamp { position: absolute; }
.tv-pdf-paper.tv-pdf-page { position: relative; }
.tv-pdf-frame.tv-pdf-page { position: relative; display: flex; flex-direction: column; }
.tv-pdf-frame.tv-pdf-page > * { flex: 0 0 auto; }

@media (max-width: 900px) {
  .tv-pdf-pages { gap: 12px; }
}
