/* =====================================================================
 * DESIGN SYSTEM -- "Arabic Quantum" token-based system, di-port 1:1 dari
 * dasbor referensi (lihat variabel --crm-*). Semua nilai visual (warna,
 * spacing, radius, shadow, font-size) WAJIB lewat token di bawah --
 * jangan hardcode hex/px langsung di rule atau di HTML (style="...").
 *
 * Bootstrap 5 (CSS + JS bundle) tetap dimuat sebagai basis utilitas
 * (grid .row/.col, .d-flex, .modal, .form-check, dst) supaya JS bawaan
 * (modal, dropdown) tidak perlu ditulis ulang -- stylesheet ini me-restyle
 * total di atasnya lewat token custom, sehingga tampilan akhir mengikuti
 * design system Arabic Quantum secara utuh (bukan tampilan Bootstrap
 * default).
 * ===================================================================== */
* { box-sizing: border-box; }

:root {
  /* =====================================================================
   * Token diselaraskan 1:1 dengan design system "Arabic Quantum" (dasbor
   * Funnel) -- flat surface, satu warna brand hijau, radius & shadow
   * berskala kecil, tanpa efek frosted-glass/blur ala iOS. Nama variabel
   * --crm-*/--app-*/--crm-glass-* DIPERTAHANKAN 1:1 (dipakai ratusan tempat
   * di seluruh app) -- hanya NILAINYA yang diganti supaya konsisten dengan
   * dasbor referensi.
   * ===================================================================== */
  --crm-brand:        #008060;
  --crm-brand-hover:  #006e52;
  --crm-brand-dark:   #00543f;
  --crm-brand-rgb:    0 128 96;
  --on-brand:        #ffffff;

  /* QR code WAJIB kontras tinggi di atas terang, terlepas dari tema aktif,
     supaya tetap bisa di-scan kamera HP -- tokenized, bukan hex lepas. */
  --qr-surface: #ffffff;

  /* Sidebar (desktop) -- flat surface putih + border tipis, senada dengan
     sidebar dasbor Funnel (tanpa frosted glass/blur). */
  --crm-sidebar-bg:     #ffffff;
  --crm-sidebar-border: #e1e3e5;
  --crm-sidebar-text:       rgba(26,26,26,0.7);
  --crm-sidebar-text-dim:   rgba(26,26,26,0.45);
  --crm-sidebar-text-faint: rgba(26,26,26,0.3);
  --crm-sidebar-hover-bg:   rgb(var(--crm-brand-rgb) / 0.08);
  --crm-sidebar-active-bg:  rgb(var(--crm-brand-rgb) / 0.12);
  --crm-sidebar-active-text: var(--crm-brand);
  --crm-sidebar-logo-text:  #1a1a1a;

  --app-body-bg:      #f4f5f7;
  --app-body-bg-rgb: 244 245 247;
  --app-surface:      #ffffff;
  --app-surface-rgb: 255 255 255;
  --app-surface-alt:  #f9fafb;
  --app-surface-alt-rgb: 249 250 251;
  --app-border:       #e1e3e5;
  --app-border-rgb: 225 227 229;
  --app-text:         #1a1a1a;
  --app-text-rgb: 26 26 26;
  --app-text-muted:   #6d7175;
  --app-text-muted-rgb: 109 113 117;
  --app-text-faint:   #6b7280;
  --app-text-faint-rgb: 107 114 128;
  --app-shadow:       rgba(0,0,0,0.06);
  --app-input-bg:     #ffffff;
  --app-input-bg-rgb: 255 255 255;
  --app-table-head:   #f9fafb;
  --app-table-head-rgb: 249 250 251;
  --app-hover:        #f6f6f7;
  --app-hover-rgb: 246 246 247;

  --app-chat-bg: #f4f5f7;
  --app-chat-bg-rgb: 244 245 247;
  --app-chat-pattern: rgba(0, 0, 0, .035);

  /* Dulu "frosted glass" (UIBlurEffect-style iOS); sekarang flat surface
     solid tanpa blur, dipakai di nav bar/tab bar/sheet, senada dasbor
     Funnel. Nama variabel dipertahankan supaya seluruh rule yang sudah
     memakainya (topbar, chat header, bottom-nav) otomatis ikut berubah. */
  --crm-glass-bg: var(--app-surface);
  --crm-glass-blur: none;
  --crm-glass-border: var(--app-border);

  /* Skala radius baku -- selaras dgn dasbor Funnel (--crm-radius-*), pakai
     salah satu dari ini, jangan angka bebas. */
  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-xl: 12px;
  --radius-full: 999px;

  --shadow-sm: 0 1px 3px rgba(0,0,0,0.06);
  --shadow-md: 0 8px 24px rgba(0,0,0,0.12);
  --shadow-lg: 0 20px 60px rgba(0,0,0,0.2);

  /* Skala spacing -- SEMUA padding (kartu/modal/overlay/halaman/baris list,
     dst) WAJIB lewat token ini, sama seperti radius/shadow/warna di atas --
     jangan hardcode "Npx" langsung di rule atau style="...". Satu token per
     nilai px yang benar-benar dipakai di codebase (bukan skala 4pt murni)
     supaya migrasinya 1:1 tanpa mengubah tampilan yang sudah pas. Tailwind
     p-*/px-*/py-* (lihat build/tailwind.config.js) di-remap ke token yang
     sama untuk nilai yang beririsan (4/8/12/16/20/32px), jadi kartu/modal
     yang pakai class Tailwind & yang pakai CSS custom sama-sama satu
     sumber. */
  --space-1px:  1px;
  --space-2px:  2px;
  --space-3px:  3px;
  --space-4px:  4px;
  --space-5px:  5px;
  --space-6px:  6px;
  --space-7px:  7px;
  --space-8px:  8px;
  --space-9px:  9px;
  --space-10px: 10px;
  --space-11px: 11px;
  --space-12px: 12px;
  --space-13px: 13px;
  --space-14px: 14px;
  --space-16px: 16px;
  --space-17px: 17px;
  --space-18px: 18px;
  --space-19px: 19px;
  --space-20px: 20px;
  --space-24px: 24px;
  --space-32px: 32px;
  --space-36px: 36px;
  --space-46px: 46px;
  --space-96px: 96px;

  /* Inter sebagai font utama (sama seperti dasbor Funnel), fallback system
     font kalau Inter belum termuat. */
  --font-sans: 'Inter', -apple-system, sans-serif;
  --text-2xs: 0.68rem;
  --text-xs:  0.75rem;
  --text-sm:  0.8rem;
  --text-base: 0.875rem;
  --text-md:  0.95rem;
  --text-lg:  1.05rem;
  --text-xl:  1.25rem;
  --text-2xl: 1.75rem;
  --text-3xl: 3rem;

  /* Warna semantik -- diselaraskan dgn token status dasbor Funnel
     (info/warning/danger/success/netral), dipakai utk teks/aksen status. */
  --crm-color-info:            #1a3d8f;
  --crm-color-info-rgb: 26 61 143;
  --crm-color-info-bg:         #dbeafe;
  --crm-color-info-border:     #b3c3f7;
  --crm-color-warning:         #7d5a00;
  --crm-color-warning-rgb: 125 90 0;
  --crm-color-warning-accent:  #f59e0b;
  --crm-color-warning-bg:      #fff8e6;
  --crm-color-warning-border:  #f0d98c;
  --crm-color-danger:          #d72c0d;
  --crm-color-danger-rgb: 215 44 13;
  --crm-color-danger-bg:       #fdecea;
  --crm-color-danger-text:     #b42318;
  --crm-color-neutral:         #9ca3af;
  --crm-color-neutral-rgb: 156 163 175;
  --crm-color-neutral-bg:      #eceef0;
  --crm-color-success:         #1a7340;
  --crm-color-success-rgb: 26 115 64;
  --crm-color-success-bg:      #d4edda;
  --crm-color-track-bg:        #eceef0;

  /* Warna ikon menu "Lainnya" (bottom-nav mobile) -- 4 kategori tetap
     dipertahankan sebagai variasi warna yang disengaja, tapi nilainya
     diredam (bukan warna neon ala iOS) supaya senada dgn palet flat
     dasbor Funnel. */
  --crm-menu-tag:            #92600b;
  --crm-menu-tag-bg:         #fff3d6;
  --crm-menu-autoreply:      #1F5C5E;
  --crm-menu-autoreply-bg:   #e3f2f2;
  --crm-menu-connect:        #1a3d8f;
  --crm-menu-connect-bg:     #dbeafe;
  --crm-menu-settings:       #008060;
  --crm-menu-settings-bg:    #f0faf6;

  /* Warna aksen kartu ringkasan Dasbor (Kontak/Broadcast/Auto Reply/Chat
     Series) -- palet sama diredamnya dengan --crm-menu-* di atas, dipakai
     di dashboard/index.php. --crm-menu-autoreply dipakai ulang (bukan
     didefinisikan lagi) supaya warnanya konsisten dengan menu Auto Reply. */
  --crm-menu-contacts:       #5b3fa8;
  --crm-menu-contacts-bg:    #efe9fb;
  --crm-menu-broadcast:      #b45309;
  --crm-menu-broadcast-bg:   #fef3e2;
  --crm-menu-chatseries:     #b81a63;
  --crm-menu-chatseries-bg:  #fde3ef;
  /* Baru: menu "Chat" pindah dari slot utama bottom-nav ke sheet "Lainnya"
     (lihat resources/views/layout/bottom-nav.php), jadi sekarang butuh
     warna ikon seperti item sheet lainnya -- belum ada sebelumnya karena
     dulu tampil di slot utama tanpa background warna. */
  --crm-menu-chat:           #0e7a5f;
  --crm-menu-chat-bg:        #e1f7ee;

  /* Palet avatar/nama pengirim grup (c2-c6; c1 = --crm-brand). Diredam dari
     versi neon iOS supaya senada dengan aksen ungu/amber/merah dasbor
     Funnel. */
  --crm-avatar-c2: #2f6fa8;
  --crm-avatar-c3: #b45309;
  --crm-avatar-c4: #6d28d9;
  --crm-avatar-c5: #be185d;
  --crm-avatar-c6: #1a7340;
  --crm-sender-c2: #2f6fa8;
  --crm-sender-c3: #b45309;
  --crm-sender-c4: #6d28d9;
  --crm-sender-c5: #be185d;
  --crm-sender-c6: #1a7340;

  --sidebar-w-expanded: 240px;
  --sidebar-w-collapsed: 76px;
  --sidebar-w: var(--sidebar-w-expanded);
  --content-offset: var(--sidebar-w);
  --topbar-height: 56px;
  --topbar-collapsed-height: 44px;
  --bottom-nav-height: 62px;
  --icon-size: 1.1rem;
}

html.sidebar-collapsed { --sidebar-w: var(--sidebar-w-collapsed); }

[data-bs-theme="dark"] {
  color-scheme: dark;

  --crm-sidebar-bg:     #1a1a2e;
  --crm-sidebar-border: rgba(255,255,255,0.08);
  --crm-sidebar-text:       rgba(255,255,255,0.65);
  --crm-sidebar-text-dim:   rgba(255,255,255,0.35);
  --crm-sidebar-text-faint: rgba(255,255,255,0.25);
  --crm-sidebar-hover-bg:   rgba(255,255,255,0.07);
  --crm-sidebar-active-bg:  rgb(var(--crm-brand-rgb) / 0.22);
  --crm-sidebar-active-text: var(--crm-brand);
  --crm-sidebar-logo-text:  #ffffff;

  --app-body-bg:      #15161a;
  --app-body-bg-rgb: 21 22 26;
  --app-surface:      #1e1f24;
  --app-surface-rgb: 30 31 36;
  --app-surface-alt:  #25262c;
  --app-surface-alt-rgb: 37 38 44;
  --app-border:       #34353c;
  --app-border-rgb: 52 53 60;
  --app-text:         #f0f0f2;
  --app-text-rgb: 240 240 242;
  --app-text-muted:   #a3a4ab;
  --app-text-muted-rgb: 163 164 171;
  --app-text-faint:   #9497a1;
  --app-text-faint-rgb: 148 151 161;
  --app-shadow:       rgba(0,0,0,0.4);
  --app-input-bg:     #25262c;
  --app-input-bg-rgb: 37 38 44;
  --app-table-head:   #25262c;
  --app-table-head-rgb: 37 38 44;
  --app-hover:        #2a2b31;
  --app-hover-rgb: 42 43 49;

  --app-chat-bg: #15161a;
  --app-chat-bg-rgb: 21 22 26;
  --app-chat-pattern: rgba(255, 255, 255, .035);

  --crm-glass-bg: var(--app-surface);
  --crm-glass-blur: none;
  --crm-glass-border: var(--app-border);

  --shadow-sm: 0 1px 3px rgba(0,0,0,0.4);
  --shadow-md: 0 8px 24px rgba(0,0,0,0.45);
  --shadow-lg: 0 20px 60px rgba(0,0,0,0.55);

  --crm-color-info:    #8fa8e8;
  --crm-color-info-rgb: 143 168 232;
  --crm-color-info-bg: rgba(29,64,175,0.2);
  --crm-color-info-border: rgba(143,168,232,0.3);
  --crm-color-warning: #fcd34d;
  --crm-color-warning-rgb: 252 211 77;
  --crm-color-warning-accent: #fbbf24;
  --crm-color-warning-bg: rgba(146,64,14,0.18);
  --crm-color-warning-border: rgba(252,211,77,0.35);
  --crm-color-danger:  #ff8a75;
  --crm-color-danger-rgb: 255 138 117;
  --crm-color-danger-bg: rgba(180,35,24,0.18);
  --crm-color-danger-text: #ff8a75;
  --crm-color-neutral: #9ca3af;
  --crm-color-neutral-rgb: 156 163 175;
  --crm-color-neutral-bg: rgba(255,255,255,0.08);
  --crm-color-success: #6ee7b7;
  --crm-color-success-rgb: 110 231 183;
  --crm-color-success-bg: rgba(26,115,64,0.18);
  --crm-color-track-bg: rgba(255,255,255,0.08);

  --crm-menu-tag:            #fcd34d;
  --crm-menu-tag-bg:         rgba(146,64,14,0.18);
  --crm-menu-autoreply:      #6ee7b7;
  --crm-menu-autoreply-bg:   rgba(31,92,94,0.25);
  --crm-menu-connect:        #93c5fd;
  --crm-menu-connect-bg:     rgba(29,64,175,0.2);
  --crm-menu-settings:       #6ee7b7;
  --crm-menu-settings-bg:    rgba(0,128,96,0.18);

  --crm-menu-contacts:       #c4b5fd;
  --crm-menu-contacts-bg:    rgba(91,63,168,0.22);
  --crm-menu-broadcast:      #fbbf24;
  --crm-menu-broadcast-bg:   rgba(180,83,9,0.22);
  --crm-menu-chatseries:     #f9a8d4;
  --crm-menu-chatseries-bg:  rgba(184,26,99,0.22);
  --crm-menu-chat:           #6ee7b7;
  --crm-menu-chat-bg:        rgba(14,122,95,0.22);

  --crm-avatar-c2: #93c5fd;
  --crm-avatar-c3: #fcd34d;
  --crm-avatar-c4: #c4b5fd;
  --crm-avatar-c5: #fda4c0;
  --crm-avatar-c6: #6ee7b7;
  --crm-sender-c2: #93c5fd;
  --crm-sender-c3: #fcd34d;
  --crm-sender-c4: #c4b5fd;
  --crm-sender-c5: #fda4c0;
  --crm-sender-c6: #6ee7b7;
}

/* ---------------------------------------------------------------------
 * Base
 * ------------------------------------------------------------------- */
html, body { height: 100%; }
body {
  background: var(--app-body-bg);
  color: var(--app-text);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  -webkit-font-smoothing: antialiased;
  transition: background 0.2s ease, color 0.2s ease;
}

/* Reset chrome bawaan <button> milik browser. Tailwind Play CDN dimuat
   dengan preflight DIMATIKAN (lihat header.php: corePlugins.preflight =
   false) supaya tidak bentrok dengan reset manual di file ini -- tapi
   reset manual itu SEBELUMNYA tidak menyertakan elemen <button>, jadi
   setiap tombol yang tidak eksplisit set border/background sendiri
   (mis. .btn-plain, atau tombol Tailwind mentah tanpa class
   border-0) tetap menampilkan kotak border UA-stylesheet browser
   sendiri (abu-abu/putih tipis) menumpuk di atas styling custom --
   inilah sumber tampilan "kotak aneh"/tidak konsisten di banyak tombol
   (Import, + Tambah, Tambah Tag, Hapus, Series Baru, dst). Satu reset
   di sini membereskan SEMUA tombol sekaligus, termasuk yang akan
   ditambahkan nanti. */
button {
  margin: 0; border-width: 0; border-style: solid; border-color: transparent;
  background: none; appearance: none; -webkit-appearance: none;
  font: inherit; color: inherit; cursor: pointer;
}
/* Catatan: sengaja border-width:0 (bukan shorthand border:none) supaya
   border-style tetap "solid" sbg basis -- beberapa tombol (mis. toggle
   Aktif/Nonaktif di chatseries/index.php) memakai utility Tailwind
   `.border` + `.border-success`/`.border-border` yang HANYA meng-override
   width & color, bukan style (preflight Tailwind dimatikan, jadi style
   dasar harus disiapkan manual di sini, bukan diwariskan browser). Kalau
   dipakai shorthand `border:none`, border-style ikut ter-reset ke "none"
   dan tidak bisa dihidupkan lagi cuma dgn override width -- border toggle
   jadi hilang. */

h1, h2, h3, h4, h5, h6 { font-weight: 700; letter-spacing: -.02em; color: var(--app-text); }
a { color: var(--crm-brand); }
/* iOS list rows must not underline links used as rows */
.crm-row, .crm-row:hover { text-decoration: none; }
code { color: var(--crm-brand-dark); }
[data-bs-theme="dark"] code { color: #6ee7b7; }
hr { border-color: var(--app-border); opacity: 1; }
small, .small { font-size: var(--text-xs); }
.text-muted { color: var(--app-text-muted) !important; }

.icon { width: var(--icon-size); height: var(--icon-size); flex-shrink: 0; vertical-align: -0.2em; }
/* Utility putar 180deg -- dipakai buat pakai ulang ikon chevron-right yg
   sudah ada jadi "chevron-left" (tombol Kembali), pola sama dgn transform
   rotate yg sudah dipakai di .sidebar-toggle-btn .icon. JANGAN bikin
   entry ikon baru "chevron-left" terpisah, cukup rotate yang ini. */
.icon-rotate-180 { transform: rotate(180deg); }
/* Chevron diputar -90deg jadi "chevron-up" -- dipakai sebagai hint visual
   swipe-up di identitas header chat (fitur mini-profil), reuse ikon
   chevron-right yang sudah ada, sama pola dengan .icon-rotate-180. */
.icon-rotate-270 { transform: rotate(-90deg); }
.icon-xs { width: 0.75rem; height: 0.75rem; }
.icon-sm { width: 0.95rem; height: 0.95rem; }
.icon-lg { width: 1.6rem; height: 1.6rem; }
.icon-xl { width: 3rem; height: 3rem; }

/* Cegah Safari iOS auto-zoom viewport saat fokus ke field form apa pun.
   Selector atribut (bukan class) sengaja dipakai supaya specificity-nya
   (0,1,1) PASTI menang dibanding utility Tailwind CDN .text-sm/.text-base
   (0,1,0) di mana pun/kapan pun kedua stylesheet itu dimuat -- pengaman
   global di luar override spesifik .crm-field-input/.chat-textarea/
   .chat-search di bawah, supaya field form manapun (termasuk yg lupa
   dikasih token/class ios) tetap aman dari zoom. */
input[type="text"], input[type="search"], input[type="tel"],
input[type="number"], input[type="email"], input[type="password"],
input[type="url"], textarea, select {
  font-size: 17px;
}

::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 4px; }
[data-bs-theme="dark"] ::-webkit-scrollbar-thumb { background: #3a3b42; }

/* ---------------------------------------------------------------------
 * Page header / title
 * ------------------------------------------------------------------- */
.page-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 20px;
}
.page-title { font-size: var(--text-xl); font-weight: 700; color: var(--app-text); letter-spacing: -.02em; }
.page-subtitle { font-size: var(--text-sm); color: var(--app-text-muted); margin-top: 2px; }

/* ---------------------------------------------------------------------
 * iOS large title (ala nav bar "Settings" besar sebelum di-scroll) --
 * dipakai di atas .crm-group pertama pada halaman gaya Settings.
 * ------------------------------------------------------------------- */
.crm-large-title { padding: var(--space-4px) var(--space-4px) var(--space-4px); margin-bottom: 4px; }
.crm-large-title h1 {
  font-size: var(--text-2xl); font-weight: 800; letter-spacing: -.025em;
  color: var(--app-text); line-height: 1.15; margin: 0;
}
.crm-large-title p { font-size: var(--text-sm); color: var(--app-text-muted); margin: 3px 0 0; }

/* ---------------------------------------------------------------------
 * iOS grouped list (ala Settings.app): label section kecil huruf kapital
 * di atas, container putih/surface rounded, baris dipisah separator tipis
 * inset (bukan garis penuh dari tepi ke tepi).
 * ------------------------------------------------------------------- */
.crm-group { margin-bottom: 22px; }
.crm-group-title {
  font-size: .72rem; font-weight: 600; text-transform: uppercase; letter-spacing: .03em;
  color: var(--app-text-muted); padding: 0 var(--space-16px) var(--space-6px); margin: 0;
}
.crm-group-footer {
  font-size: .78rem; color: var(--app-text-muted); padding: var(--space-6px) var(--space-16px) 0; margin: 0; line-height: 1.4;
}
.crm-list {
  background: var(--app-surface);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  border: 1px solid var(--crm-glass-border, var(--app-border));
}
.crm-row {
  display: flex; align-items: center; gap: 12px;
  min-height: 44px; padding: var(--space-11px) var(--space-16px);
  background: transparent; color: var(--app-text);
  position: relative; width: 100%; text-align: left; border: none;
  font-family: inherit; font-size: var(--text-base); cursor: pointer;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
a.crm-row, button.crm-row { transition: background-color .1s ease; }
a.crm-row:active, button.crm-row:active, .crm-row.is-pressed { background: var(--app-hover); }
/* separator inset ala iOS -- mulai dari setelah ikon/avatar, bukan dari tepi */
.crm-list > .crm-row:not(:last-child)::after,
.crm-list > *:not(:last-child) > .crm-row::after {
  content: ''; position: absolute; left: 16px; right: 0; bottom: 0; height: 1px;
  background: var(--app-border); transform: scaleY(.6);
}
.crm-list > .crm-row.crm-row-inset:not(:last-child)::after,
.crm-list > *:not(:last-child) > .crm-row.crm-row-inset::after { left: 52px; }
.crm-row-icon {
  flex-shrink: 0; width: 29px; height: 29px; border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  background: var(--crm-brand); color: #fff;
  font-weight: 700; font-size: .8rem;
}
.crm-row-icon .icon { width: 16px; height: 16px; }
.crm-row-icon.is-neutral { background: var(--app-text-faint); }
.crm-panel { padding: var(--space-24px) var(--space-20px); }

/* =====================================================================
 * Dasbor -- kartu ringkasan (Kontak/Broadcast/Auto Reply/Chat Series) +
 * daftar "5 Chat Terakhir". Grid 2 kolom di mobile, 4 kolom di desktop;
 * kartu pakai token surface/border/radius/shadow yang sama dgn komponen
 * lain (BUKAN warna/ukuran bebas), cuma aksen ikon per kartu yang beda
 * lewat var(--crm-menu-*). Lihat resources/views/dashboard/index.php.
 * ===================================================================== */
.dash-stats-grid {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; margin-bottom: 22px;
}
@media (min-width: 640px) {
  .dash-stats-grid { grid-template-columns: repeat(4, 1fr); }
}
/* Modifier: dipaksa 3 kolom di SEMUA ukuran layar (mobile & desktop),
   dipakai di halaman Rincian Broadcast (broadcast/report.php) yang
   datanya selalu tepat 3 kartu (Terkirim/Gagal/Menunggu) -- beda dgn
   grid Dasbor yang 2/4 kolom karena isinya 4 kartu menu. */
.dash-stats-grid.is-report3 { grid-template-columns: repeat(3, 1fr); }
@media (min-width: 640px) {
  .dash-stats-grid.is-report3 { grid-template-columns: repeat(3, 1fr); }
}
.dash-stat-card {
  display: flex; flex-direction: column; gap: 10px;
  background: var(--app-surface); border: 1px solid var(--app-border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  padding: var(--space-14px); text-decoration: none; transition: transform .12s ease, box-shadow .12s ease;
}
a.dash-stat-card:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }
a.dash-stat-card:active { transform: translateY(0); }
.dash-stat-icon {
  width: 34px; height: 34px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.dash-stat-icon .icon { width: 18px; height: 18px; }
.dash-stat-value { font-size: var(--text-2xl); font-weight: 700; color: var(--app-text); line-height: 1.15; }
.dash-stat-label { font-size: var(--text-xs); color: var(--app-text-muted); font-weight: 500; }

/* Baris "5 Chat Terakhir" -- reuse .chat-avatar (warna & inisial identik
   dengan daftar Chat) tapi dibungkus .crm-row/.crm-list supaya menyatu
   dengan pola grouped-list dasbor, bukan style .chat-list-item terpisah. */
.dash-chat-row .chat-avatar { margin: 0; }
.dash-chat-row .crm-row-body { margin-left: 2px; }
.dash-chat-time { font-size: var(--text-xs); color: var(--app-text-muted); flex-shrink: 0; white-space: nowrap; }
.dash-chat-unread {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 var(--space-5px); border-radius: 999px;
  background: var(--crm-brand); color: var(--on-brand);
  font-size: .65rem; font-weight: 700; flex-shrink: 0;
}
.crm-list form { margin: 0; }
.crm-list form:not(:last-child) { position: relative; }
.crm-row-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.crm-row-title { color: var(--app-text); font-weight: 400; line-height: 1.3; }
.crm-row.is-strong .crm-row-title { font-weight: 600; }
.crm-row-subtitle { font-size: var(--text-xs); color: var(--app-text-muted); margin-top: 1px; }
.crm-row-value {
  flex-shrink: 0; color: var(--app-text-muted); font-size: var(--text-base);
  max-width: 55%; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.crm-row-chevron { flex-shrink: 0; width: 17px; height: 17px; color: var(--app-text-muted); }
.crm-row.is-accent { color: var(--crm-brand); }
.crm-row.is-accent .crm-row-title { color: var(--crm-brand); font-weight: 500; }
.crm-row.is-destructive .crm-row-title { color: var(--crm-color-danger); font-weight: 400; }
.crm-row.is-destructive.is-strong .crm-row-title { font-weight: 600; }
.crm-row.is-center { justify-content: center; text-align: center; }
.crm-row.is-center .crm-row-title { text-align: center; }
.crm-row-avatar { flex-shrink: 0; }

/* status dot -- satu-satunya pemakaian warna semantik non-biru di app ini,
   persis pola titik status di Settings/Bluetooth iOS. */
.crm-status { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-sm); color: var(--app-text-muted); }
.crm-status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--app-text-faint); flex-shrink: 0; }
.crm-status.is-live .crm-status-dot { background: var(--crm-color-success); box-shadow: 0 0 0 3px rgba(52,199,89,.18); }
.crm-status.is-pending .crm-status-dot { background: var(--crm-color-warning); box-shadow: 0 0 0 3px rgba(255,149,0,.18); }
.crm-status.is-off .crm-status-dot { background: var(--app-text-faint); }

/* =====================================================================
 * "Command Deck" -- komponen bersama utk redesain canvas Broadcast /
 * Kontak / Chat Series (varian A dari mockup redesain, panel geser
 * kanan/drawer). Namespace ".cmd-*" supaya tidak bentrok dgn komponen
 * grouped-list ".crm-*" yang sudah ada -- canvas ini tetap DUDUK DI ATAS
 * .crm-list/.crm-row/.crm-group yang sama (daftar penerima/kontak/tag),
 * cuma header ringkasannya (chip status + ring progres + pill status per
 * baris) yang dapat bahasa visual baru. SEMUA nilai warna/radius/shadow/
 * spacing/font di bawah ini WAJIB lewat token --crm-*/--app-*/--radius-*/
 * --shadow-*/--space-*/--text-* yang sudah ada di :root/[data-bs-theme]
 * di atas -- TIDAK ADA hex/px baru yang di-hardcode, supaya otomatis
 * mengikuti tema terang/gelap yang sudah berjalan (lihat theme.js).
 * ===================================================================== */

/* Chip status di bawah tombol kembali (pengganti .crm-status polos utk
   konteks canvas ini) -- latar tinted memakai token *-bg yang sama dgn
   status semantik lain di app ini (info/warning/danger/success/neutral),
   BUKAN warna baru. */
.cmd-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--text-xs); font-weight: 700;
  padding: var(--space-4px) var(--space-10px) var(--space-4px) var(--space-8px);
  border-radius: var(--radius-full); margin-bottom: var(--space-10px);
}
.cmd-chip-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.cmd-chip.is-live    { background: var(--crm-color-success-bg); color: var(--crm-color-success); }
.cmd-chip.is-live    .cmd-chip-dot { background: var(--crm-color-success); box-shadow: 0 0 0 3px rgb(var(--crm-color-success-rgb) / .18); }
.cmd-chip.is-pending { background: var(--crm-color-warning-bg); color: var(--crm-color-warning); }
.cmd-chip.is-pending .cmd-chip-dot { background: var(--crm-color-warning-accent); box-shadow: 0 0 0 3px rgb(var(--crm-color-warning-rgb) / .18); }
.cmd-chip.is-info    { background: var(--crm-color-info-bg); color: var(--crm-color-info); }
.cmd-chip.is-info    .cmd-chip-dot { background: var(--crm-color-info); box-shadow: 0 0 0 3px rgb(var(--crm-color-info-rgb) / .18); }
.cmd-chip.is-danger  { background: var(--crm-color-danger-bg); color: var(--crm-color-danger-text, var(--crm-color-danger)); }
.cmd-chip.is-danger  .cmd-chip-dot { background: var(--crm-color-danger); box-shadow: 0 0 0 3px rgb(var(--crm-color-danger-rgb) / .18); }
.cmd-chip.is-off     { background: var(--app-surface-alt); color: var(--app-text-muted); }
.cmd-chip.is-off     .cmd-chip-dot { background: var(--app-text-faint); }

/* Sub-judul kecil di bawah judul canvas (mis. "205 penerima total"). */
.cmd-drawer-sub { font-size: var(--text-xs); color: var(--app-text-muted); }

/* Ring progres tunggal -- pengganti grid 3 kartu stat terpisah
   (.dash-stats-grid.is-report3) di canvas ini. Proporsi terkirim/gagal
   dikirim per-instance lewat custom property --cmd-p1 (akhir segmen
   "terkirim", dlm %) & --cmd-p2 (akhir segmen "gagal", dlm %) yang
   di-set inline oleh PHP (report.php) / JS (drawer di index.php) --
   itu DATA dinamis per broadcast, bukan token desain yang di-hardcode. */
.cmd-ring-block { display: flex; align-items: center; gap: var(--space-16px); padding: var(--space-4px) var(--space-16px) var(--space-4px); }
.cmd-ring {
  --cmd-p1: 0%; --cmd-p2: 0%;
  width: 96px; height: 96px; border-radius: var(--radius-full); flex-shrink: 0;
  /* BUG FIX: sebelumnya cuma "display:flex" tanpa flex-direction, jadi
     ikut default row -- angka besar (b) & label (small) di dalam
     lubang donut malah sejajar HORIZONTAL alih-alih bertumpuk vertikal,
     meluber keluar lingkaran dalam. flex-direction:column supaya
     keduanya bertumpuk & selalu center di dalam lubang, seberapa pun
     lebar teksnya. */
  display: flex; flex-direction: column; align-items: center; justify-content: center; position: relative;
  background: conic-gradient(var(--crm-color-success) 0 var(--cmd-p1), var(--crm-color-danger) var(--cmd-p1) var(--cmd-p2), var(--crm-color-track-bg) var(--cmd-p2) 100%);
}
.cmd-ring::after { content: ""; position: absolute; inset: var(--space-9px); border-radius: 50%; background: var(--app-surface); }
/* Isi lubang donut (angka + label) -- dibungkus 1 wrapper (bukan b/small
   langsung sbg flex item) supaya lebar teks dibatasi persis diameter
   lubang (96px - 2*9px inset = 78px) & responsif menyusut kalau
   angkanya banyak digit, TANPA meluber ke luar lingkaran. */
.cmd-ring-inner { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; width: calc(100% - 2 * var(--space-9px)); max-width: 100%; padding: 0 var(--space-3px); }
.cmd-ring b { font-size: clamp(0.85rem, 4vw, var(--text-lg)); font-weight: 800; color: var(--app-text); line-height: 1.1; }
.cmd-ring small { font-size: var(--text-2xs); color: var(--app-text-muted); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; display: block; text-align: center; margin-top: 1px; white-space: nowrap; }
.cmd-ring-legend { display: flex; flex-direction: column; gap: var(--space-9px); flex: 1; min-width: 0; }
.cmd-ring-li { display: flex; align-items: center; justify-content: space-between; gap: var(--space-8px); font-size: var(--text-sm); }
.cmd-ring-key { display: flex; align-items: center; gap: var(--space-7px); color: var(--app-text-muted); font-weight: 600; min-width: 0; }
.cmd-ring-li b { font-size: var(--text-md); font-weight: 800; color: var(--app-text); flex-shrink: 0; }
.cmd-ring-dot { width: 8px; height: 8px; border-radius: var(--radius-xs); flex-shrink: 0; }
.cmd-ring-dot.is-sent    { background: var(--crm-color-success); }
.cmd-ring-dot.is-failed  { background: var(--crm-color-danger); }
.cmd-ring-dot.is-pending { background: var(--app-text-faint); }

/* Avatar persegi membulat -- modifier di atas .chat-avatar.avatar-cN yang
   sudah ada (warna per-baris TETAP dari palet --crm-avatar-c*/--crm-brand
   yang sama), cuma bentuknya diubah dari lingkaran penuh jadi rounded-
   square ala "Command Deck". */
.cmd-avatar { border-radius: var(--radius-lg); }

/* Pill status per-baris (pengganti .crm-status bertitik utk daftar
   penerima/kontak/langkah di canvas ini) -- latar solid tinted, sama
   persis pasangan token *-bg/warna teks yang dipakai kartu ringkasan
   Dasbor (dash-stat-icon) supaya konsisten satu sistem warna. */
.cmd-pill {
  display: inline-flex; align-items: center; flex-shrink: 0;
  font-size: var(--text-2xs); font-weight: 800; text-transform: uppercase; letter-spacing: .03em;
  padding: var(--space-3px) var(--space-8px); border-radius: var(--radius-sm);
}
.cmd-pill.is-sent    { background: var(--crm-color-success-bg); color: var(--crm-color-success); }
.cmd-pill.is-failed  { background: var(--crm-color-danger-bg); color: var(--crm-color-danger-text, var(--crm-color-danger)); }
.cmd-pill.is-pending { background: var(--app-surface-alt); color: var(--app-text-muted); }
/* Alias tone generik (is-success/is-neutral/is-danger) -- nilai token
   sama persis dgn is-sent/is-pending/is-failed di atas, cuma nama beda
   supaya masuk akal dipakai di konteks non-broadcast (status enrollment
   Chat Series, dst) tanpa "is-sent" yang aneh kalau bukan soal kirim
   pesan. */
.cmd-pill.is-success { background: var(--crm-color-success-bg); color: var(--crm-color-success); }
.cmd-pill.is-neutral { background: var(--app-surface-alt); color: var(--app-text-muted); }
.cmd-pill.is-danger  { background: var(--crm-color-danger-bg); color: var(--crm-color-danger-text, var(--crm-color-danger)); }

/* Tag chip interaktif di canvas Kontak (drawer profil) -- restyle dari
   ".drawer-tag-toggle" versi lama (masih dipakai apa adanya oleh JS di
   contacts/index.php, cuma tampilannya disamakan dgn bahasa "Command
   Deck"). Warna titik & fill saat aktif TETAP dari --tag-color (warna tag
   custom per-user, di-set inline oleh JS), BUKAN token baru -- itu memang
   data, bukan desain. */
.cmd-tag {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--app-border); background: var(--app-surface-alt); color: var(--app-text-muted);
  border-radius: var(--radius-md); padding: var(--space-6px) var(--space-11px);
  font-size: var(--text-sm); font-weight: 600; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.cmd-tag::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--tag-color); flex-shrink: 0; }
.cmd-tag.is-active { background: var(--tag-color); border-color: var(--tag-color); color: var(--on-brand); }

/* Kartu pesan -- restyle dari bubble chat (.drawer-msg-in/out lama) jadi
   kartu flat ala Command Deck (border tipis, bukan ekor bubble), tetap
   beda arah masuk/keluar lewat align-self & tint brand utk pesan keluar. */
.cmd-msgcard { border-radius: var(--radius-lg); padding: var(--space-11px) var(--space-13px); font-size: var(--text-sm); line-height: 1.5; max-width: 92%; background: var(--app-surface-alt); border: 1px solid var(--app-border); color: var(--app-text); }
.cmd-msg-list { display: flex; flex-direction: column; gap: var(--space-8px); padding: 0 var(--space-16px); }
.cmd-msgcard:not(.is-out) { align-self: flex-start; }
.cmd-msgcard.is-out { background: rgb(var(--crm-brand-rgb) / .08); border-color: rgb(var(--crm-brand-rgb) / .25); color: var(--crm-brand); align-self: flex-end; }
.cmd-msgcard-time { display: block; font-size: var(--text-2xs); color: var(--app-text-faint); margin-top: 6px; }

/* Grid mini-stat 3 kolom (mis. Langkah/Nomor/Selesai di canvas Chat
   Series) -- beda dari .dash-stats-grid/.dash-stat-card (Dasbor & lama
   Rincian Broadcast): ini dipakai INLINE di bawah judul canvas, kotak
   lebih kecil/padat tanpa ikon, cuma angka + label. */
.cmd-statgrid { display: flex; gap: var(--space-8px); }
.cmd-stat { flex: 1; background: var(--app-surface-alt); border: 1px solid var(--app-border); border-radius: var(--radius-md); padding: var(--space-8px); text-align: center; }
.cmd-stat b { display: block; font-size: var(--text-lg); font-weight: 800; color: var(--app-text); line-height: 1.15; }
.cmd-stat span { font-size: var(--text-2xs); color: var(--app-text-faint); text-transform: uppercase; font-weight: 700; letter-spacing: .03em; }

/* Timeline langkah (canvas Chat Series) -- node bulat bernomor + garis
   penghubung vertikal, node "selesai/aktif" ditandai tint hijau (reuse
   token --crm-color-success/-bg yang sama dgn pill "Terkirim" di
   Broadcast, BUKAN warna baru). */
.cmd-timeline { position: relative; }
.cmd-tstep { display: flex; gap: var(--space-12px); position: relative; padding-bottom: var(--space-18px); }
.cmd-tstep::before { content: ""; position: absolute; left: 13px; top: 26px; bottom: 0; width: 1.5px; background: var(--app-border); }
.cmd-tstep:last-child::before { display: none; }
.cmd-tnode { width: 27px; height: 27px; border-radius: 50%; background: var(--app-surface-alt); border: 1.5px solid var(--app-border); display: flex; align-items: center; justify-content: center; font-size: var(--text-2xs); font-weight: 800; color: var(--app-text-muted); flex-shrink: 0; }
.cmd-tstep.is-done .cmd-tnode { background: var(--crm-color-success-bg); border-color: var(--crm-color-success); color: var(--crm-color-success); }
.cmd-tbody { flex: 1; min-width: 0; padding-top: 2px; display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-8px); }
.cmd-tbody-main { min-width: 0; }
.cmd-ttime { font-size: var(--text-xs); color: var(--app-text-faint); font-weight: 600; }
.cmd-tname { font-size: var(--text-sm); font-weight: 700; margin-top: 1px; color: var(--app-text); white-space: pre-wrap; }
.cmd-tactions { display: flex; gap: var(--space-4px); flex-shrink: 0; }

/* CTA "+ Tambah Langkah" bergaya dashed -- pengganti baris
   .crm-row.is-accent di dalam .crm-list yang sebelumnya dipakai utk aksi
   ini, sesuai bahasa "Command Deck" pada mockup (kotak putus-putus,
   bukan baris grouped-list). */
.cmd-addstep {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; border: 1.5px dashed var(--app-border); border-radius: var(--radius-md);
  padding: var(--space-12px); font-size: var(--text-sm); font-weight: 700;
  color: var(--crm-brand); background: transparent; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.cmd-addstep:hover { background: rgb(var(--crm-brand-rgb) / .06); border-color: var(--crm-brand); }

/* ---------------------------------------------------------------------
 * iOS buttons -- filled (System Blue, tombol utama full-width) & plain
 * text button (aksi sekunder/link).
 * ------------------------------------------------------------------- */
.btn-block {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 50px; width: 100%; padding: 0 var(--space-18px);
  border-radius: var(--radius-lg); border: none;
  font-size: var(--text-md); font-weight: 600; font-family: inherit;
  cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: opacity .12s ease, transform .08s ease;
}
.btn-block:active { transform: scale(.985); opacity: .85; }
.btn-block:disabled { opacity: .45; cursor: not-allowed; transform: none; }
.btn-block-filled { background: var(--crm-brand); color: #fff; }
.btn-block-tinted { background: rgb(var(--crm-brand-rgb) / .12); color: var(--crm-brand); }
.btn-block-destructive-tinted { background: var(--crm-color-danger-bg); color: var(--crm-color-danger); }
.btn-plain { background: transparent; border: none; color: var(--crm-brand); min-height: 34px; padding: 0 var(--space-4px); font-size: var(--text-base); }
/* Modifier: tombol teks di header modal/drawer (Batal/Simpan/Lanjutkan)
   -- tidak butuh area sentuh 34px minimum karena sudah ada di dalam
   baris header yang punya tinggi sendiri. Sebelumnya ditulis berulang
   lewat style="min-height:auto" inline di contacts/index.php. */
.btn-plain.is-compact { min-height: auto; }

/* ---------------------------------------------------------------------
 * Tombol baris/aksi inline (.btn-*) -- versi ringkas dari .btn-block
 * untuk konteks yang BUKAN tombol aksi utama full-width (mis. "Hapus"
 * di baris tabel, "Edit" di kartu, header aksi sekunder). Sebelumnya
 * tiap halaman (Tag, Chat Series, Auto Reply, Pengaturan) menulis ulang
 * string utility Tailwind yang sama persis (8-12 kelas) berkali-kali --
 * dikonsolidasikan di sini jadi satu set kelas bernama, memakai token
 * warna yang SAMA PERSIS dengan sebelumnya (lihat mapping warna
 * Tailwind di layout/header.php: brand/surface-alt/text-muted/danger
 * semuanya = var(--crm-*)/var(--app-*) yang sama), jadi TIDAK ADA
 * perubahan visual -- murni konsolidasi supaya satu tampilan tombol
 * diubah di satu tempat, bukan puluhan tempat.
 * ------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  border-radius: var(--radius-md); border: 1px solid transparent;
  font-family: inherit; font-size: var(--text-sm); font-weight: 600;
  text-decoration: none; cursor: pointer; touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: background-color .12s ease, color .12s ease, border-color .12s ease;
}
.btn:disabled { opacity: .5; cursor: not-allowed; }

.btn-sm { height: 36px; padding: 0 var(--space-12px); }
.btn-lg { min-height: 44px; padding: 0 var(--space-16px); }
.btn-icon { width: 36px; height: 36px; padding: 0; flex-shrink: 0; }
.btn-icon-round { width: 32px; height: 32px; padding: 0; border-radius: var(--radius-full); flex-shrink: 0; }

.btn-brand { background: var(--crm-brand); color: var(--on-brand); border-color: var(--crm-brand); }
.btn-brand:hover { background: var(--crm-brand-hover); border-color: var(--crm-brand-hover); }

.btn-outline-brand { background: transparent; color: var(--crm-brand); border-color: var(--crm-brand); }
.btn-outline-brand:hover { background: var(--crm-brand); color: var(--on-brand); }

.btn-neutral { background: var(--app-surface-alt); color: var(--app-text-muted); border-color: var(--app-border); }
.btn-neutral:hover { background: var(--app-hover); color: var(--app-text); }

.btn-danger { background: transparent; color: var(--crm-color-danger-text); border-color: var(--crm-color-danger); }
.btn-danger:hover { background: var(--crm-color-danger-bg); }

.btn-plain-round { background: transparent; color: var(--app-text-muted); border-color: transparent; }
.btn-plain-round:hover { background: var(--app-hover); color: var(--app-text); }

/* ---------------------------------------------------------------------
 * iOS segmented control (ala tab QR/Kode Pairing) -- 1 aksen biru,
 * sisanya abu netral.
 * ------------------------------------------------------------------- */
.crm-segment {
  display: flex; align-items: center; gap: 2px;
  background: var(--app-surface-alt); border-radius: 9px; padding: var(--space-2px);
}
.btn-segment {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 32px; border: none; border-radius: var(--radius-md); background: transparent;
  color: var(--app-text-muted); font-size: var(--text-sm); font-weight: 600; font-family: inherit;
  cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: background-color .15s ease, color .15s ease, box-shadow .15s ease;
}
.btn-segment.is-active { background: var(--app-surface); color: var(--crm-brand); box-shadow: 0 1px 3px rgba(0,0,0,.12); }
[data-bs-theme="dark"] .btn-segment.is-active { background: #48484a; color: var(--crm-brand); }

/* ---------------------------------------------------------------------
 * Frosted glass surface helper -- dipakai untuk sheet/panel tambahan
 * kalau dibutuhkan di luar nav bar/tab bar bawaan.
 * ------------------------------------------------------------------- */
.crm-glass {
  background: var(--crm-glass-bg);
  -webkit-backdrop-filter: var(--crm-glass-blur);
  backdrop-filter: var(--crm-glass-blur);
  border: 1px solid var(--crm-glass-border);
}

/* ---------------------------------------------------------------------
 * Redesign Broadcast (iOS) -- tambahan komponen dipakai pertama kali di
 * resources/views/broadcast/{index,create,report}.php. Prinsip sama
 * dengan session/connect.php: satu aksen System Blue, sisanya netral;
 * hijau/oranye/merah CUMA buat titik status kecil, bukan warna baru di
 * elemen lain.
 * ------------------------------------------------------------------- */

/* 2 modifier .crm-status tambahan: is-info (biru, "Selesai") & is-danger
   (merah, "Gagal") -- pola identik dgn is-live/is-pending/is-off. */
.crm-status.is-info .crm-status-dot { background: var(--crm-brand); box-shadow: 0 0 0 3px rgb(var(--crm-brand-rgb) / .18); }
.crm-status.is-danger .crm-status-dot { background: var(--crm-color-danger); box-shadow: 0 0 0 3px rgba(255,59,48,.18); }

/* Link-area parsial (ikon+judul) di dalam .crm-row yang juga punya
   elemen non-link lain sebagai sibling (mis. tombol aksi/mini form) --
   dibutuhkan karena <button>/<form> tidak boleh nested di dalam <a>. */
.crm-row-linkgroup {
  display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0;
  text-decoration: none; color: inherit;
}

/* Tombol pill mini inline di dalam .crm-row (mis. "Mulai"/"Jeda" di
   baris broadcast) -- lebih kecil dari .btn-block biasa. Tinted biru cuma
   buat aksi utama; abu netral buat aksi sekunder/non-destruktif. */
.crm-row-action {
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  min-height: 30px; padding: 0 var(--space-12px); border-radius: var(--radius-full); border: none;
  font-size: var(--text-xs); font-weight: 600; font-family: inherit;
  cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: opacity .12s ease, transform .08s ease;
}
.crm-row-action:active { transform: scale(.94); opacity: .8; }
.crm-row-action .icon { width: 13px; height: 13px; }
.crm-row-action.is-tinted { background: rgb(var(--crm-brand-rgb) / .12); color: var(--crm-brand); }
.crm-row-action.is-neutral-tinted { background: var(--app-surface-alt); color: var(--app-text-muted); }
[data-bs-theme="dark"] .crm-row-action.is-neutral-tinted { background: #2c2c2e; }

/* Aksi cepat per baris (Chat/Edit/Hapus/Mulai/Jeda dst) -- bulat tinted
   ikon-saja, dipakai di SEMUA halaman list (Kontak, Broadcast, Auto Reply,
   Chat Series). Komponen bersama, JANGAN didefinisikan ulang secara lokal
   per halaman -- sama seperti aturan ".switch" di atas. */
.row-action-group { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; }
.btn-row-action.crm-row-action { width: 30px; padding: 0; }

/* Baris preview 1-line (mis. cuplikan pesan balasan Auto Reply) di dalam
   .crm-row-subtitle -- dipotong dgn ellipsis, bukan wrap. */
.crm-row-preview { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }

/* Progress bar tipis (ala progres unduh App Store) -- satu-satunya isian
   warna System Blue, track-nya abu netral. */
.crm-progress { height: 3px; border-radius: var(--radius-full); background: var(--crm-color-track-bg); overflow: hidden; margin-top: 5px; max-width: 220px; }
.crm-progress > span { display: block; height: 100%; background: var(--crm-brand); border-radius: inherit; }

/* Form field ala Settings iOS: label kecil di atas + input/textarea/
   berdiri sendiri (border+radius per-input, ala kartu form standalone) --
   .crm-list yang isinya field otomatis "dilepas" boxing grouped-list-nya
   lewat :has() di bawah, supaya tidak dobel kotak (kotak row + kotak
   input). Warna fokus & radius TETAP lewat token (--crm-brand/--radius-lg)
   supaya ikut warna brand yang diatur di halaman Pengaturan, bukan hardcode. */
.crm-field { display: flex; flex-direction: column; width: 100%; gap: 6px; }
.crm-field-label { font-size: var(--text-sm); font-weight: 700; color: var(--app-text); }
.crm-field-input, .crm-field-textarea, .crm-field-select {
  border: 1.5px solid var(--app-border); background: var(--app-surface);
  border-radius: 9px; outline: none; width: 100%; padding: var(--space-10px) var(--space-12px);
  /* 16px tetap (bukan var(--text-base)/14px) -- ini batas AMAN minimum:
     di bawah 16px, Safari iOS otomatis zoom-in seluruh viewport saat field
     ini difokus. Jangan diturunkan lagi walau teks lain di app pakai 14px. */
  font-size: 16px; font-family: inherit; color: var(--app-text);
  transition: border-color .15s ease;
}
.crm-field-input:focus, .crm-field-textarea:focus, .crm-field-select:focus {
  border-color: var(--crm-brand);
}
.crm-field-textarea { min-height: 72px; resize: vertical; line-height: 1.45; }
/* Placeholder TIDAK kena batas 16px di atas (cuma berlaku selagi kosong,
   jadi aman dari zoom) -- turunkan ke --text-base spy sekilas senada dgn
   ukuran teks lain di app, beda dgn teks yg sudah diketik user (16px). */
.crm-field-input::placeholder, .crm-field-textarea::placeholder {
  color: var(--app-text-faint); font-size: var(--text-base);
}
.crm-field-select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%238e8e93' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center; background-size: 16px; padding-right: var(--space-36px);
}
.crm-row.is-field { align-items: flex-start; padding: 0; }
.crm-row.is-split { gap: 20px; }
/* Baris field 2 kolom (mis. Jeda+Satuan, Minimum+Maksimum). .crm-field
   punya width:100% bawaan (dipakai utk baris field tunggal) -- di dalam
   .is-split itu bentrok dgn flexbox: width:100% jadi flex-basis, jadi
   kolom manapun yang dipaksa flex:0 0 auto lewat inline style ikut
   mengklaim basis 100% lebar baris & TIDAK menyusut, sehingga kolom lain
   gepeng dan kolom ini mepet/overflow ke tepi. Reset eksplisit di sini:
   default kolom split melar rata (flex:1 1 0%), kolom .is-fixed baru
   dikunci lebarnya (min-width via var, bukan style="..." per halaman). */
.crm-row.is-split > .crm-field { flex: 1 1 0%; width: auto; min-width: 0; }
.crm-row.is-split > .crm-field.is-fixed { flex: 0 0 auto; min-width: var(--space-96px); }
/* .crm-list di dalam offcanvas-body (drawer) -- .offcanvas-body TIDAK
   punya padding kiri/kanan (beda dari halaman biasa yang gutter-nya dari
   main.app-main), jadi tiap .crm-list yg langsung jadi isi section drawer
   perlu margin kiri/kanan sendiri, atau ke-4 sudutnya mepet ke tepi layar
   (tidak senada dgn section lain di drawer yg sudah dikasih inset 16px). */
.crm-list.is-inset { margin: 0 var(--space-16px); }
/* Baris list biasa (bukan form field) yang butuh isi rata-atas -- mis.
   baris "Nomor Terdaftar" berisi avatar+judul+subtitle 2 baris + badge
   status. TIDAK pakai .is-field supaya padding 16px & boxing .crm-list
   (background/border/shadow) tidak ikut lepas -- itu penyebab gap
   kiri/kanan hilang di baris ini sebelumnya. */
.crm-row.is-top { align-items: flex-start; }
/* .crm-list yang HANYA berisi baris field: lepas boxing grouped-list
   (background/border/shadow/hairline) supaya tiap field tampil sebagai
   kotak sendiri (bukan kotak di dalam kotak). .crm-list yang isinya baris
   navigasi/toggle biasa (tanpa is-field) tidak kena, tetap boxed seperti
   semula. */
.crm-list:has(> .crm-row.is-field) {
  background: none; border: none; box-shadow: none; border-radius: 0;
  display: flex; flex-direction: column; gap: 14px; overflow: visible;
}
.crm-list:has(> .crm-row.is-field) > .crm-row.is-field::after { content: none; }
/* Grup yg isinya field standalone (lihat blok di atas) melepas padding
   kiri/kanan .crm-list-nya jadi 0 supaya kotak field berdiri sendiri --
   tapi .crm-group-title/.crm-group-footer di atas & bawahnya masih pakai
   padding 16px bawaan, jadi teks label section menjorok ke kanan dibanding
   tepi kiri kotak field persis di bawahnya. Nolkan juga di sini supaya
   label, footer, dan field-nya rata kiri-kanan dalam satu grup. */
.crm-group:has(> .crm-list > .crm-row.is-field) > .crm-group-title,
.crm-group:has(> .crm-list > .crm-row.is-field) > .crm-group-footer {
  padding-left: 0; padding-right: 0;
}

/* Swatch warna ala trailing accessory di baris Settings iOS (dipakai di
   modal Tag Baru/Edit Tag) -- pengganti <input type="color"> bertepi
   kotak Tailwind generik yang sebelumnya dipakai. */
.crm-color-input {
  -webkit-appearance: none; appearance: none;
  width: 40px; height: 28px; padding: 0; margin: 0; flex-shrink: 0;
  border: 1px solid var(--app-border); border-radius: 8px;
  background: none; cursor: pointer;
}
.crm-color-input::-webkit-color-swatch-wrapper { padding: 0; border-radius: 7px; overflow: hidden; }
.crm-color-input::-webkit-color-swatch { border: none; border-radius: 7px; }
.crm-color-input::-moz-color-swatch { border: none; border-radius: 7px; }

/* Checkbox ala iOS Contacts multi-select -- accent-color bikin browser
   render checkbox pakai style sistem (biru saat dicentang). */
.checkbox { width: 22px; height: 22px; accent-color: var(--crm-brand); cursor: pointer; flex-shrink: 0; }

/* ---------------------------------------------------------------------
 * Bulk-edit generik (checkbox per baris + toolbar aksi massal) dipakai
 * di Broadcast/Auto Reply/Chat Series -- pola sama dengan
 * .contact-bulk-bar milik Kontak (lihat resources/views/contacts/index.php),
 * tapi dijadikan komponen bersama di sini karena dipakai di 3 halaman
 * grouped-list (.crm-row) sekaligus. Toolbar SELALU tampil (bukan
 * hidden/show) begitu ada minimal 1 baris, supaya checkbox "pilih semua"
 * selalu bisa dijangkau -- tombol aksi (Duplikat/Hapus) di-disable lewat
 * atribut `disabled` sampai ada baris yang dicentang.
 * ------------------------------------------------------------------- */
.crm-row-check { flex-shrink: 0; display: flex; align-items: center; cursor: pointer; padding-right: var(--space-2px); }

/* Tag chip -- dipakai di halaman Tag, badge tag di Kontak, filter tag di
   Kontak, dan pemilih tag di Broadcast (buat campaign). SEBELUMNYA
   didefinisikan ulang 3x terpisah per halaman dengan padding/border yang
   sedikit beda-beda (tidak seragam) -- sekarang SATU definisi bersama di
   sini. JANGAN didefinisikan ulang secara lokal per halaman, pakai class
   ".tag-chip" ini di mana pun dibutuhkan (sama seperti aturan ".switch"). */
.tag-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: var(--space-3px) var(--space-10px); border-radius: 999px; font-size: var(--text-sm); font-weight: 600;
  background: color-mix(in srgb, var(--tag-color) 16%, transparent);
  color: var(--tag-color); border: 1px solid color-mix(in srgb, var(--tag-color) 40%, transparent);
  white-space: nowrap;
}
.tag-chip::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--tag-color); flex-shrink: 0; }
.tag-chip-sm { padding: var(--space-1px) var(--space-8px); font-size: var(--text-xs); gap: 5px; }
.tag-chip-sm::before { width: 6px; height: 6px; }
.crm-bulk-bar {
  display: flex; align-items: center; gap: 14px; padding: var(--space-9px) var(--space-16px);
  background: color-mix(in srgb, var(--crm-brand) 6%, var(--app-surface));
  border-bottom: 1px solid var(--app-border); flex-wrap: wrap;
}
.crm-bulk-count { font-size: var(--text-sm); color: var(--app-text); }

/* Konsistensi radius (fix): .crm-bulk-bar duduk sebagai sibling LANGSUNG
   sebelum .crm-list di dalam .crm-group, dipakai di Broadcast/Kontak/Chat
   Series/Auto Reply/Tag -- sebelumnya bar ini tidak punya border/
   border-radius sama sekali, jadi sudut atasnya selalu siku sementara
   .crm-list di bawahnya rounded sendiri (2 kartu terpisah, radius tidak
   nyambung). Khusus Kontak dulu ini "tersamarkan" karena bulk-bar-nya
   sempat dibungkus wrapper ".crm-list.overflow-hidden" ekstra yang beda
   dari pola halaman lain (lihat contacts/index.php) -- wrapper itu sudah
   dihapus supaya markup-nya sama persis, jadi rule di bawah ini kini
   berlaku identik di semua halaman list. Rule ini menyatukan .crm-bulk-bar
   + .crm-list jadi SATU kartu rounded yang sama secara visual. JANGAN
   dipakai di luar pola ".crm-group > .crm-bulk-bar", biar tidak menimpa
   markup lain yang mungkin memakai .crm-bulk-bar dengan struktur beda
   (mis. dibungkus wrapper rounded sendiri, seperti #contactCardList di
   Kontak -- lihat rule ".crm-group > .contact-toolbar ~ ..." khusus di
   contacts/index.php untuk kasus itu). */
.crm-group > .crm-bulk-bar {
  border: 1px solid var(--crm-glass-border, var(--app-border));
  border-bottom: 1px solid var(--app-border);
  border-top-left-radius: var(--radius-md);
  border-top-right-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}
.crm-group > .crm-bulk-bar + .crm-list {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  border-top: none;
  box-shadow: none;
}
.btn-plain:disabled { opacity: .35; pointer-events: none; cursor: default; }

/* Switch on/off ala iOS Settings -- dipakai untuk semua toggle boolean
   satu-pilihan di app ini (Auto Reply/Chat Series "Aktif"/"Berlaku juga
   untuk grup", dsb). Komponen bersama supaya semua toggle tampil
   konsisten; JANGAN didefinisikan ulang secara lokal per halaman --
   pakai class ".switch" ini di mana pun dibutuhkan.
   Beda dari .checkbox: .checkbox untuk multi-select (pilih banyak
   item dari daftar, juga dipakai di login "Ingat saya"), .switch untuk
   satu pengaturan on/off. */
.switch { display: inline-flex; position: relative; width: 51px; height: 31px; flex-shrink: 0; margin-left: auto; }
.switch input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; z-index: 2; }
.switch .track { position: absolute; inset: 0; border-radius: 999px; background: var(--crm-color-track-bg); transition: background-color .2s ease; }
.switch .thumb { position: absolute; top: 2px; left: 2px; width: 27px; height: 27px; border-radius: 999px; background: #ffffff; box-shadow: 0 3px 8px rgba(0,0,0,.18), 0 1px 1px rgba(0,0,0,.16); transition: transform .2s ease; }
.switch input:checked ~ .track { background: var(--crm-brand); }
.switch input:checked ~ .thumb { transform: translateX(20px); }
.switch input:focus-visible ~ .track { box-shadow: 0 0 0 3px rgba(var(--crm-brand-rgb), .35); }

/* ---------------------------------------------------------------------
 * Select kustom -- pengganti picker NATIVE OS untuk semua <select
 * class="crm-field-select">. Sebelumnya tap select memunculkan dialog
 * bawaan Android/iOS (radio bulat biru sistem, tidak bisa di-restyle,
 * tidak konsisten dgn sisa app) -- sekarang di-progressive-enhance oleh
 * public/assets/js/select-enhance.js jadi:
 *  1) tombol trigger (.crm-select-trigger) -- visual 100% identik dgn
 *     .crm-field-select asli (dipakai ulang, BUKAN didefinisikan lagi),
 *  2) bottom sheet (.crm-select-backdrop/.crm-select-sheet) berisi
 *     .crm-list/.crm-row -- pola SAMA PERSIS dgn sheet pemilih Nomor WA
 *     (topbar.php) & pemilih grup chat (chat/index.php): opsi terpilih
 *     ditandai .is-strong + ikon check (.crm-row-chevron), tanpa radio
 *     bulat baru. <select> aslinya TETAP ada di DOM (disembunyikan lewat
 *     .crm-select-native) supaya name=/value= submit form tidak berubah.
 * JANGAN didefinisikan ulang secara lokal per halaman -- semua select
 * cukup pakai class ".crm-field-select" seperti biasa, select-enhance.js
 * otomatis membungkusnya di halaman manapun (termasuk isi modal).
 * ------------------------------------------------------------------- */
.crm-select-native { display: none !important; }
.crm-select-trigger { display: flex; align-items: center; justify-content: space-between; text-align: left; }
.crm-select-trigger:disabled { opacity: .5; cursor: default; }

.crm-select-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,.45); z-index: 90;
  opacity: 0; visibility: hidden; transition: opacity .2s ease, visibility .2s ease;
}
.crm-select-backdrop.is-open { opacity: 1; visibility: visible; }
.crm-select-sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 91;
  background: var(--crm-glass-bg);
  -webkit-backdrop-filter: var(--crm-glass-blur);
  backdrop-filter: var(--crm-glass-blur);
  border-radius: 18px 18px 0 0;
  box-shadow: var(--shadow-lg);
  max-height: 78vh; display: flex; flex-direction: column;
  padding: var(--space-8px) var(--space-18px) calc(var(--space-18px) + env(safe-area-inset-bottom, 0px));
  transform: translateY(100%);
  transition: transform .28s cubic-bezier(.32,.72,0,1);
}
.crm-select-sheet.is-open { transform: translateY(0); }
/* Wrapper scroll internal -- handle+header+search tetap diam, cuma
   .crm-list di dalamnya yang scroll kalau opsinya banyak. */
.crm-select-sheet-body { overflow-y: auto; min-height: 0; }
.crm-select-search { margin-bottom: 10px; flex-shrink: 0; }
.crm-select-empty { padding: var(--space-16px) var(--space-4px); text-align: center; color: var(--app-text-muted); font-size: var(--text-sm); }
/* SENGAJA tanpa breakpoint desktop yang mengubah sheet jadi dialog
   tengah -- di app ini sheet pemilihan (WA session/grup chat, lihat
   .crm-more-sheet + override #waSessionSheet/#groupSheet di atas) SELALU
   tampil sebagai bottom sheet di semua ukuran layar, tidak pernah
   berubah bentuk di desktop. Select kustom mengikuti pola yang sama
   persis supaya konsisten. */

/* ---------------------------------------------------------------------
 * FIX: modal/drawer wrapper (.app-modal, dulu cuma utility Tailwind
 * "fixed inset-0 z-[70]" tanpa overflow) TIDAK BISA discroll begitu isi
 * form-nya lebih tinggi dari layar -- sisa field & tombol "Simpan" di
 * bawah jadi tidak terjangkau sama sekali (mentok, tidak bisa disimpan).
 * Kejadian di semua modal Buat/Edit yang formnya panjang: Auto Reply,
 * Chat Series (+ Tambah/Edit Step), Pengaturan (Branding/Koneksi/Status),
 * Tag, Kontak. Wrapper ini sendiri (BUKAN body dalamnya) yang dijadikan
 * area scroll, sama seperti pola modal Tailwind standar -- <body> tetap
 * dikunci (.overflow-hidden, lihat openModal() per halaman) supaya cuma
 * modal-nya yang scroll, bukan halaman di belakangnya.
 * ------------------------------------------------------------------- */
.app-modal { overflow-y: auto; -webkit-overflow-scrolling: touch; }

/* ---------------------------------------------------------------------
 * Buttons -- bare .btn dkk (dulu di-restyle di atas Bootstrap) sudah tidak
 * dipakai satu pun view (semua tombol pakai utility Tailwind langsung).
 * .btn-icon-only DIPERTAHANKAN: dipakai nyata di chat/index.php (tombol
 * kirim) & bukan turunan Bootstrap .btn, jadi bukan dead code.
 * ------------------------------------------------------------------- */
.btn-icon-only .icon { margin-right: 0; }

/* ---------------------------------------------------------------------
 * Cards / surfaces -- .card/.card-body/.card-title (Bootstrap) sudah tidak
 * dipakai; halaman yang dulu pakai .card sekarang pakai .connect-card
 * (custom, lihat bawah) atau utility Tailwind rounded-lg/border/shadow-sm
 * langsung.
 * ------------------------------------------------------------------- */
.surface-muted { background-color: var(--app-surface-alt); border-radius: var(--radius-md); }
.max-w-form { max-width: 640px; }
.scroll-max-h { max-height: 260px; overflow-y: auto; }
.border.rounded-3 { border-color: var(--app-border) !important; }

/* ---------------------------------------------------------------------
 * Table -- .table/.table-responsive-wrap (Bootstrap) sudah tidak dipakai;
 * semua tabel sekarang <table class="w-full ..."> + .bg-table-head utility
 * Tailwind langsung (lihat autoreply/chatseries/tags/contacts/broadcast).
 * ------------------------------------------------------------------- */
.status-icon-cell { width: 2.5rem; }

/* Data list -- kartu-versi tabel untuk mobile (custom, BUKAN Bootstrap,
   dipakai nyata via row.matches('.data-list-item') dkk di contacts/index.php
   -- jangan dihapus/diganti nama). */
.data-list { display: flex; flex-direction: column; }
.data-list-item { padding: var(--space-16px); border-bottom: 1px solid var(--app-border); }
.data-list-item:last-child { border-bottom: none; }
/* Poin "seragamkan list": kartu Kontak (contact_row_html mode 'card') pakai
   class data-list-item HANYA sebagai penanda buat JS (lihat komentar di
   contacts/index.php & helpers.php) -- baris ini sekarang dibungkus
   .crm-list, jadi reset padding/border bawaan .data-list-item supaya
   .crm-row yang menentukan tampilan (padding & separator inset ala iOS),
   sama persis dengan list lain (Broadcast/Tag/Auto Reply/Chat Series/dst). */
.data-list-item.crm-row { padding: var(--space-11px) var(--space-16px); border-bottom: none; }
.data-list-item-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.data-list-item-title { font-weight: 700; word-break: break-word; color: var(--app-text); }
.data-list-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: var(--text-sm); padding-block: .2rem; }
.data-list-row-label { color: var(--app-text-muted); flex-shrink: 0; }
.data-list-row-value { text-align: right; }

/* ---------------------------------------------------------------------
 * Badge / Alert / Nav pills / Modal (Bootstrap) -- semua sudah dikonversi
 * ke utility Tailwind + token warna (bg-success-bg/text-success dkk, lihat
 * tailwind.config di header.php), jadi rule .badge/.alert/.nav-pills/
 * .modal-content di sini sudah dead code dan dilepas di Tahap 5.
 * ------------------------------------------------------------------- */

/* ---------------------------------------------------------------------
 * App shell -- sidebar (desktop, collapsible)
 * ------------------------------------------------------------------- */
.app-shell { min-height: 100vh; }

#sidebar {
  width: var(--sidebar-w);
  background: var(--crm-sidebar-bg);
  -webkit-backdrop-filter: var(--crm-glass-blur);
  backdrop-filter: var(--crm-glass-blur);
  border-right: 1px solid var(--crm-sidebar-border);
  position: fixed;
  top: 0; left: 0; bottom: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
  overflow-y: auto;
  transition: width 0.25s ease, background 0.2s ease, border-color 0.2s ease;
}
.sidebar-logo {
  padding: var(--space-16px) var(--space-16px) var(--space-10px);
  display: flex; align-items: center; gap: 10px;
  min-height: 40px;
}
.sidebar-logo-text {
  font-size: var(--text-sm); font-weight: 700; color: var(--crm-sidebar-logo-text);
  letter-spacing: .04em; flex: 1; white-space: nowrap; overflow: hidden;
}
.sidebar-nav { flex: 1; padding: var(--space-12px) 0; }
.nav-section-label {
  font-size: var(--text-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: var(--crm-sidebar-text-dim); padding: var(--space-14px) var(--space-20px) var(--space-5px); white-space: nowrap; overflow: hidden;
}
/* Catatan: dulu selector ganda ".sidebar .nav-link, #sidebar .nav-item"
   (Bootstrap .nav-link + custom .nav-item) -- ".sidebar .nav-link" dead,
   sidebar.php cuma pakai .nav-item, jadi disederhanakan di Tahap 5. */
#sidebar .nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: var(--space-8px) var(--space-12px); margin: 1px 8px;
  border-radius: var(--radius-sm);
  color: var(--crm-sidebar-text);
  font-size: var(--text-base); font-weight: 500;
  text-decoration: none;
  transition: background .15s, color .15s;
}
#sidebar .nav-item:hover { background: var(--crm-sidebar-hover-bg); color: var(--crm-sidebar-active-text); }
#sidebar .nav-item.active { background: var(--crm-sidebar-active-bg); color: var(--crm-sidebar-active-text); font-weight: 700; }
#sidebar .nav-item .icon { opacity: .75; flex-shrink: 0; }
#sidebar .nav-item.active .icon { opacity: 1; }
.nav-item-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.sidebar-toggle-row-bottom { display: flex; justify-content: center; padding: var(--space-10px) var(--space-16px); border-top: 1px solid var(--crm-sidebar-border); }
.sidebar-toggle-btn {
  flex-shrink: 0; display: flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: var(--radius-md); border: none; background: transparent;
  color: var(--crm-sidebar-text-dim); cursor: pointer;
}
.sidebar-toggle-btn:hover { background: var(--crm-sidebar-hover-bg); color: var(--crm-sidebar-logo-text); }
.sidebar-toggle-btn .icon { transition: transform .25s ease; transform: rotate(180deg); }
html.sidebar-collapsed .sidebar-toggle-btn .icon { transform: rotate(0deg); }

.sidebar-footer { padding: var(--space-10px) var(--space-16px); border-top: 1px solid var(--crm-sidebar-border); font-size: .65rem; color: var(--crm-sidebar-text-faint); text-align: center; white-space: nowrap; overflow: hidden; }

html.sidebar-collapsed .sidebar-logo-text,
html.sidebar-collapsed .nav-section-label,
html.sidebar-collapsed .nav-item-label,
html.sidebar-collapsed .sidebar-footer { display: none; }
html.sidebar-collapsed .sidebar-logo { justify-content: center; padding: var(--space-16px) var(--space-4px) var(--space-10px); }
html.sidebar-collapsed #sidebar .nav-item { justify-content: center; padding: var(--space-10px) var(--space-8px); margin: 3px 10px; }

/* ---------------------------------------------------------------------
 * Top bar (fixed, dipakai desktop & mobile)
 * ------------------------------------------------------------------- */
#topbar {
  background: var(--crm-glass-bg);
  -webkit-backdrop-filter: var(--crm-glass-blur);
  backdrop-filter: var(--crm-glass-blur);
  border-bottom: 1px solid var(--crm-glass-border);
  height: var(--topbar-height);
  position: fixed;
  top: 0; left: var(--content-offset); right: 0;
  z-index: 30;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 var(--space-20px);
  box-sizing: border-box;
  transition: left 0.25s ease, height .18s ease, padding .18s ease;
}
.topbar-title { font-size: var(--text-base); font-weight: 600; color: var(--app-text); letter-spacing: -.01em; }
.topbar-left { display: flex; align-items: center; gap: 12px; min-width: 0; }
.topbar-right { display: flex; align-items: center; gap: 8px; }

.sidebar-hamburger-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border: 1px solid var(--app-border); border-radius: var(--radius-md);
  background: var(--app-surface-alt); color: var(--app-text-muted); cursor: pointer; flex-shrink: 0;
}
.sidebar-hamburger-btn:hover { color: var(--app-text); background: var(--app-hover); }

.topbar-logout {
  display: inline-flex; align-items: center; gap: 6px; padding: var(--space-6px) var(--space-12px);
  color: var(--app-text-muted); font-size: var(--text-sm); font-weight: 500;
  border: 1px solid var(--app-border); border-radius: var(--radius-sm); text-decoration: none;
  background: transparent; cursor: pointer; transition: background .15s, color .15s;
}
.topbar-logout:hover { background: var(--crm-color-danger-bg); color: var(--crm-color-danger); border-color: var(--crm-color-danger); }
[data-bs-theme="dark"] .topbar-logout:hover { background: var(--crm-color-danger-bg); border-color: var(--crm-color-danger); color: var(--crm-color-danger); }

.theme-switch { display: inline-flex; background: var(--app-surface-alt); border: 1px solid var(--app-border); border-radius: var(--radius-md); padding: var(--space-2px); gap: 2px; }
.btn-theme { display: inline-flex; align-items: center; gap: 5px; padding: var(--space-5px) var(--space-10px); border: none; border-radius: var(--radius-md); background: transparent; color: var(--app-text-muted); font-size: .72rem; font-weight: 600; cursor: pointer; transition: all .15s; }
.btn-theme span { display: none; }
.btn-theme:hover { color: var(--app-text); }
.btn-theme.is-active { background: var(--app-surface); color: var(--crm-brand); box-shadow: 0 1px 2px var(--app-shadow); }
@media (min-width: 480px) { .btn-theme span { display: inline; } }

/* ---------------------------------------------------------------------
 * Main content offset
 * ------------------------------------------------------------------- */
#main-wrapper { display: flex; min-height: 100vh; }
main.app-main { flex: 1; margin-left: var(--content-offset); margin-top: var(--topbar-height); padding: var(--space-24px); min-width: 0; transition: margin-left .25s ease; max-width: 1180px; }

@media (max-width: 1023.98px) {
  main.app-main { padding: var(--space-16px); padding-bottom: calc(var(--bottom-nav-height) + env(safe-area-inset-bottom, 0px) + var(--space-16px)); }
  :root { --content-offset: 0px; }
  #sidebar { display: none !important; }
  .sidebar-hamburger-btn { display: none !important; }
}

/* ---------------------------------------------------------------------
 * Topbar -- pemilih nomor WA aktif (pill trigger + sheet, lihat
 * layout/topbar.php). Trigger pakai kapsul netral ala pill "Storage" di
 * Settings iOS (bukan tombol Tailwind mentah spt sebelumnya); isi sheet-
 * nya reuse .crm-list/.crm-row (grouped list yang sama dgn Pengaturan
 * Sesi) di dalam .crm-more-sheet (komponen bottom sheet yang sama dgn
 * sheet "Lainnya"/pilih grup chat) -- supaya trigger, isi, dan sheet-nya
 * 100% konsisten dgn sistem desain iOS yang sudah dipakai di app ini.
 * ------------------------------------------------------------------- */
.topbar-session-btn {
  display: inline-flex; align-items: center; gap: 7px;
  height: 32px; padding: 0 var(--space-13px) 0 var(--space-11px); border-radius: var(--radius-full);
  background: var(--app-surface-alt); border: 1px solid var(--app-border);
  color: var(--app-text-muted); font-family: inherit; font-size: var(--text-sm);
  font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -.01em;
  cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: background-color .1s ease, color .1s ease;
  max-width: 46vw;
}
.topbar-session-btn .icon { color: var(--app-text-muted); }
.topbar-session-btn span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar-session-btn:hover, .topbar-session-btn:active, .topbar-session-btn.active {
  background: var(--app-hover); color: var(--app-text);
}

/* ---------------------------------------------------------------------
 * Bottom navbar (mobile) + sheet "Lainnya"
 * ------------------------------------------------------------------- */
.bottom-nav { display: none; }

@media (max-width: 1023.98px) {
  .bottom-nav {
    display: flex;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
    background: var(--crm-glass-bg);
    -webkit-backdrop-filter: var(--crm-glass-blur);
    backdrop-filter: var(--crm-glass-blur);
    border-top: 1px solid var(--crm-glass-border);
    box-shadow: none;
    padding: var(--space-6px) var(--space-4px) calc(var(--space-6px) + env(safe-area-inset-bottom, 0px));
    justify-content: space-between; align-items: stretch;
  }
}

/* Catatan: ".bottom-nav .nav-link" (Bootstrap) dead, bottom-nav.php cuma
   pakai .crm-mnav-item -- disederhanakan di Tahap 5. */
.crm-mnav-item {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; padding: var(--space-6px) var(--space-2px); border: none; background: transparent; color: var(--app-text-muted);
  text-decoration: none; font-size: .62rem; font-weight: 600; line-height: 1.15;
  border-radius: 10px; cursor: pointer; transition: color .15s, background .15s; min-width: 0;
}
.crm-mnav-item span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.crm-mnav-item .icon { width: 20px; height: 20px; flex-shrink: 0; }
.crm-mnav-item:hover { color: var(--app-text); background: var(--app-hover); }
.crm-mnav-item.active { color: var(--crm-brand); font-weight: 700; }

.crm-more-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,.45); z-index: 55;
  opacity: 0; visibility: hidden; transition: opacity .2s ease, visibility .2s ease;
}
.crm-more-backdrop.is-open { opacity: 1; visibility: visible; }

.crm-more-sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 56;
  background: var(--crm-glass-bg);
  -webkit-backdrop-filter: var(--crm-glass-blur);
  backdrop-filter: var(--crm-glass-blur);
  border-radius: 18px 18px 0 0;
  box-shadow: var(--shadow-lg);
  max-height: 82vh; overflow-y: auto;
  padding: var(--space-8px) var(--space-18px) calc(var(--space-18px) + env(safe-area-inset-bottom, 0px));
  transform: translateY(100%);
  transition: transform .28s cubic-bezier(.32,.72,0,1);
}
.crm-more-sheet.is-open { transform: translateY(0); }

/* Fix: dropdown pindah workspace di baris search (chat-list-wa-toggle)
   tidak kelihatan/tidak bisa diklik saat drawer daftar chat (.chat-list)
   sedang terbuka -- sheet ini reuse .crm-more-sheet/.crm-more-backdrop
   yang z-index dasarnya cuma 55/56, sedangkan .chat-list drawer sendiri
   z-index:70 (+ .chat-list-backdrop z-index:65). Klik tombolnya SUDAH
   menambah class .is-open dgn benar (JS tidak bermasalah), tapi secara
   visual sheet & backdrop-nya numpuk DI BELAKANG drawer, jadi kelihatan
   seperti "tidak bereaksi". Override by-ID di sini (bukan naikkan
   .crm-more-sheet/.crm-more-backdrop generik) supaya sheet "Lainnya"/
   pilih grup/pilih nomor WA di tempat lain (topbar, bottom-nav) yang
   tidak pernah tumpang tindih dgn drawer ini tidak ikut berubah. */
#chatEmptyWaSessionBackdrop { z-index: 75; }
#chatEmptyWaSessionSheet { z-index: 76; }
.crm-more-handle { width: 36px; height: 4px; border-radius: var(--radius-full); background: var(--app-border); margin: 6px auto 10px; }
.crm-more-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.crm-more-title { font-size: var(--text-md); font-weight: 700; color: var(--app-text); }
.crm-more-close { background: var(--app-surface-alt); border: none; border-radius: 50%; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; color: var(--app-text-muted); cursor: pointer; touch-action: manipulation; }
.crm-more-close:hover { color: var(--app-text); }
.crm-more-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px 6px; margin-bottom: 8px; }
.crm-more-grid-item { display: flex; flex-direction: column; align-items: center; gap: 7px; text-decoration: none; color: var(--app-text); text-align: center; }
.crm-more-grid-icon { width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; border-radius: 14px; }
.crm-more-grid-icon .icon { width: 21px; height: 21px; }
.crm-more-grid-label { font-size: .68rem; font-weight: 600; line-height: 1.2; }
.crm-more-grid-item.active .crm-more-grid-label { color: var(--crm-brand); }
.crm-more-footer { display: flex; align-items: center; justify-content: space-between; border-top: 1px solid var(--app-border); margin-top: 8px; padding-top: var(--space-12px); font-size: var(--text-xs); color: var(--app-text-muted); }
.crm-more-logout { display: inline-flex; align-items: center; gap: 5px; color: var(--crm-color-danger); text-decoration: none; font-weight: 600; background: none; border: none; cursor: pointer; font-size: var(--text-xs); }

@media (min-width: 1024px) { .crm-more-backdrop, .crm-more-sheet { display: none !important; } }

/* Poin 3 (fix): sheet "Lainnya" (#aqMoreSheet) memang mobile-only karena
   digantikan sidebar di layar besar -- tapi sheet pilih grup (#groupSheet)
   ikut ke-hide juga karena sebelumnya reuse class .crm-more-sheet yang sama.
   Override khusus by-ID di sini supaya sheet grup tetap bisa dipakai user
   desktop, tanpa mengubah perilaku sheet "Lainnya". */
@media (min-width: 1024px) {
  #groupSheetBackdrop, #groupSheet { display: block !important; }
}

/* Sheet pemilih nomor WA (topbar) -- sama seperti #groupSheet di atas,
   dipakai lintas ukuran layar (desktop pakai trigger pill di topbar,
   bukan cuma bottom-nav mobile). */
@media (min-width: 1024px) {
  #waSessionBackdrop, #waSessionSheet { display: block !important; }
}

/* ---------------------------------------------------------------------
 * Login (auth) -- 100% pakai token & komponen yang sama dengan dasbor:
 * .page-header/.page-title/.page-subtitle, .card/.card-body, .form-label/
 * .form-control, .input-group/.input-group-text (pola sama dgn form nomor
 * HP di session/connect.php), .btn-success/.btn-outline-secondary, dan
 * .theme-switch topbar. Tidak ada nilai visual baru di luar token
 * --crm-, --app-, --radius-, --shadow- yang sudah dipakai di dasbor.
 * ------------------------------------------------------------------- */
.auth-shell {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex; align-items: center; justify-content: center;
  /* Padding hormati safe-area notch/home-indicator, sama seperti pola
     mobile-polish yang sudah dipakai di halaman Chat. */
  padding: calc(var(--space-24px) + env(safe-area-inset-top, 0px)) var(--space-20px) calc(var(--space-24px) + env(safe-area-inset-bottom, 0px));
  background: var(--app-body-bg); /* sama persis dgn body dasbor, bukan gradient custom */
}
.auth-shell-inner { width: 100%; max-width: 400px; }

/* Brand mark -- versi skala-besar dari .sidebar-logo (ikon dalam kotak
   membulat berwarna brand + nama app), dipusatkan karena halaman ini
   berdiri sendiri tanpa sidebar/topbar. */
.auth-brand-mark { display: flex; align-items: center; justify-content: center; gap: 12px; margin-bottom: 24px; }
.auth-brand-icon {
  flex-shrink: 0; width: 44px; height: 44px; border-radius: var(--radius-lg);
  background: rgb(var(--crm-brand-rgb) / .12); color: var(--crm-brand);
  display: flex; align-items: center; justify-content: center;
}
.auth-brand-icon .icon { width: 1.4rem; height: 1.4rem; }
.auth-brand-text { text-align: left; }
.auth-brand-name { font-size: var(--text-lg); font-weight: 700; color: var(--app-text); line-height: 1.2; }
.auth-brand-tagline { font-size: var(--text-xs); color: var(--app-text-muted); }

/* Page header -- reuse .page-header apa adanya, cuma dipusatkan (di dasbor
   rata kiri karena sejajar tombol aksi; di sini murni judul + subjudul). */
.auth-page-header { display: block; text-align: center; margin-bottom: 16px; }
.auth-page-header .page-title { font-size: var(--text-lg); }

.auth-card { width: 100%; }

/* "Ingat saya" -- checkbox + label polos tanpa card/kotak pembungkus
   (beda dari .crm-row biasa yang selalu hidup di dalam .crm-list). */
.auth-remember-row {
  display: flex; align-items: center; gap: 10px;
  font-size: var(--text-base); color: var(--app-text);
  margin: -6px 0 20px;
}

/* Tombol lihat/sembunyi password di dalam input-group -- ukuran & area
   sentuh sama dgn tombol ikon-saja lain di dasbor (mis. .chat-back-btn).
   .crm-field-input-wrap = konteks posisi supaya tombol mata inset di
   DALAM kotak input (bukan mengambang di sisinya) -- input dikasih
   padding-right ekstra biar teks tidak ketiban ikon. */
.crm-field-input-wrap { position: relative; }
.crm-field-input-wrap .crm-field-input { padding-right: var(--space-46px); }
.crm-field-input-wrap .auth-toggle-password {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
}
.auth-toggle-password { flex-shrink: 0; display: flex; align-items: center; justify-content: center; width: 44px; touch-action: manipulation; }
.auth-eye-hide { display: none; }
.auth-toggle-password.is-showing .auth-eye-show { display: none; }
.auth-toggle-password.is-showing .auth-eye-hide { display: inline; }

.auth-footnote { margin-top: 16px; }

/* Theme switch pill floating -- komponen identik 1:1 dengan .theme-switch
   di topbar dasbor (lihat resources/views/layout/topbar.php), cuma
   diposisikan fixed karena halaman login tidak punya topbar sendiri. */
.theme-switch-floating {
  position: fixed; top: calc(16px + env(safe-area-inset-top, 0px)); right: 16px; z-index: 1030;
}

/* ---------------------------------------------------------------------
 * Chat
 * ------------------------------------------------------------------- */
/* ---------------------------------------------------------------------
 * Fix: komposer chat terdorong keluar viewport di HP
 * -----------------------------------------------------------------------
 * Akar masalah #1 (sudah diperbaiki sebelumnya): tinggi .chat-shell dihitung
 * pakai calc() yang tidak menghitung tinggi .page-header, jadi shell selalu
 * lebih tinggi dari viewport tersisa -> composer harus di-scroll manual.
 *
 * Akar masalah #2 (gap besar antara composer & keyboard virtual, screenshot
 * user 2026-08-16): tanpa flag `interactive-widget=resizes-content` di meta
 * viewport (lihat resources/views/layout/header.php), browser Android
 * modern (Chrome/Brave) TIDAK benar-benar me-resize layout viewport saat
 * keyboard muncul -- cuma visualViewport yang menyusut, dan trik JS
 * (syncViewportHeight -> --crm-vvh) yang mengandalkan itu punya jeda/quirk
 * timing yang bikin komposer "berhenti" beberapa puluh px sebelum keyboard.
 * Fix: (a) tambahkan interactive-widget=resizes-content di meta viewport
 * supaya browser me-resize layout SECARA NATIVE, persis kayak app chat
 * lain (WA/Telegram) atau app ini sendiri; (b) unit fallback diganti dari
 * 100vh ke 100dvh (dynamic viewport height) yang juga ikut menyusut
 * otomatis kalau flag di atas tidak didukung (mis. Safari lama). JS
 * --crm-vvh tetap dipertahankan sebagai lapis fallback tambahan.
 *
 * Perbaikan: khusus halaman Chat (ditandai `body.crm-chat-page`, di-set
 * server-side di resources/views/layout/header.php berdasar path request --
 * jadi sudah aktif SEBELUM render pertama, tidak nunggu JS), main.app-main
 * dibuat flex column dengan tinggi PERSIS viewport yang tersisa (topbar +
 * safe-area keyboard via --crm-vvh yang sudah ada). .page-header dibiarkan
 * natural (flex-shrink: 0), sisa ruang otomatis mengalir ke .chat-shell
 * (flex: 1) -- tidak perlu lagi menebak tinggi page-header di angka
 * calc() manual, dan tidak mungkin overflow lagi berapa pun tinggi
 * page-header berubah. */
body.crm-chat-page main.app-main {
  display: flex;
  flex-direction: column;
  height: calc(100dvh - var(--topbar-height));
  overflow: hidden;
}
@media (max-width: 767.98px) {
  body.crm-chat-page main.app-main {
    /* --crm-vvh (visualViewport, di-set lewat JS) menyusut otomatis saat
       keyboard virtual muncul -- lihat syncViewportHeight() di chat/index.php. */
    height: calc(var(--crm-vvh, 100dvh) - var(--topbar-height));
  }
}
body.crm-chat-page .page-header { flex-shrink: 0; }
body.crm-chat-page .chat-shell { flex: 1; min-height: 0; height: auto; }

/* Chat sedang dibuka di mode single-pane mobile: sembunyikan .page-header
   sepenuhnya (bukan cuma dikecilkan) supaya SEMUA ruang vertikal ekstra
   langsung dipakai .chat-shell -- selaras dengan Poin 11 di bawah yang
   sudah menyembunyikan bottom-nav pada kondisi yang persis sama. */
body.crm-chat-open .page-header { display: none; }

/* Catatan: .chat-shell HANYA pernah dirender di halaman /chat, dan body
   selalu dapat class .crm-chat-page di halaman itu (lihat $isChatPage di
   layout/header.php) -- jadi override `body.crm-chat-page .chat-shell`
   di atas SELALU menang atas `height`/`min-height` di bawah ini (dead
   code sebelumnya, sekarang dihapus supaya tidak menyesatkan orang yang
   membaca/debug tinggi .chat-shell). Sisa properti (border/radius/
   overflow/background/shadow) tetap aktif seperti biasa. */
.chat-shell {
  display: flex;
  border: 1px solid var(--app-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background-color: var(--app-surface);
  box-shadow: var(--shadow-sm);
}
@media (max-width: 1023.98px) {
  .chat-shell { height: calc(100vh - var(--topbar-height) - var(--bottom-nav-height) - 32px); }
}
/* Poin 5: di HP, pakai tinggi viewport aktual (--crm-vvh, di-set lewat JS
   window.visualViewport) supaya composer tidak ketutup keyboard virtual --
   100vh/vh unit CSS biasa tidak menyusut otomatis saat keyboard muncul di
   banyak browser mobile. Fallback ke perhitungan lama kalau JS belum jalan. */
@media (max-width: 767.98px) {
  .chat-shell {
    height: calc(var(--crm-vvh, 100dvh) - var(--topbar-height) - var(--bottom-nav-height) - 32px);
  }
}

/* Poin 1: single-pane di mobile -- tampilkan daftar chat ATAU panel
   percakapan dalam satu waktu, dengan tombol kembali di header panel.
   CATATAN (bug fix terbaru): sejak layout drawer ala Claude AI Android
   diterapkan, `.chat-list` dan `.chat-panel` DI SINI sudah kalah
   spesifisitas / sudah dipaksa override oleh blok
   "body.claude-chat-page .chat-shell.claude-shell ..." di bawah (chat-list
   selalu display:flex, visibilitasnya murni via transform; chat-panel
   selalu full width). Baris .chat-list & .chat-panel di blok ini praktis
   tidak lagi berefek pada halaman /chat -- JANGAN taruh display:none pada
   .chat-list di sini lagi, itu yang dulu bikin tombol hamburger drawer
   "tidak ada reaksi" saat sebuah chat sedang aktif. Dibiarkan apa adanya
   (tidak dihapus) supaya tidak berisiko untuk pemakaian .chat-shell di
   luar /chat kalau ada di masa depan. */
@media (max-width: 767.98px) {
  .chat-shell { border-radius: var(--radius-md); }
  .chat-list { width: 100%; display: flex; }
  .chat-panel { display: none; }
  .chat-back-btn { display: inline-flex; }

  .chat-shell.has-active .chat-list { display: none; }
  .chat-shell.has-active .chat-panel { display: flex; width: 100%; }
}

/* Poin 10 (root fix): fallback JS untuk deteksi mobile, lapis kedua di luar
   CSS media query. Kalau breakpoint 767.98px di atas gagal ter-trigger
   (mis. karena viewport meta non-standar, embed/iframe, atau bug spesifik
   browser tertentu), script di chat/index.php mengukur lebar .chat-shell
   sendiri lewat ResizeObserver + matchMedia sebagai cadangan, lalu memaksa
   class `.js-force-single-pane` di bawah ini -- isinya SENGAJA duplikat
   1:1 dari blok media query Poin 1 di atas supaya hasil akhirnya identik,
   terlepas dari media query aslinya jalan atau tidak. */
.chat-shell.js-force-single-pane { border-radius: var(--radius-md); }
.chat-shell.js-force-single-pane .chat-list { width: 100%; display: flex; }
.chat-shell.js-force-single-pane .chat-panel { display: none; }
.chat-shell.js-force-single-pane .chat-back-btn { display: inline-flex; }
.chat-shell.js-force-single-pane.has-active .chat-list { display: none; }
.chat-shell.js-force-single-pane.has-active .chat-panel { display: flex; width: 100%; }

/* Poin 11: reclaim ruang layar -- saat satu chat sedang terbuka di mobile,
   bottom-nav (5 ikon) disembunyikan total. Tombol kembali di header panel
   sudah cukup jadi jalan keluar (pola standar WA/Telegram), dan ruang
   vertikal ekstra langsung dipakai buat pesan. Class `.crm-chat-open`
   di-toggle lewat JS di chat/index.php, cuma aktif saat mode single-pane
   DAN ada percakapan yang sedang dibuka.
   Trik: --bottom-nav-height di-override jadi 0px di scope body ini, jadi
   SEMUA formula calc() yang sudah memakai var(--bottom-nav-height) --
   padding-bottom main.app-main, tinggi .chat-shell, posisi toast copy --
   otomatis ikut menyesuaikan tanpa perlu ditulis ulang satu-satu. */
body.crm-chat-open { --bottom-nav-height: 0px; }
body.crm-chat-open .bottom-nav { display: none; }

/* Poin 17: fullscreen tanpa header -- saat satu chat dibuka di mobile,
   #topbar (nama halaman, hamburger, pemilih nomor WA) disembunyikan TOTAL
   (bukan cuma dikecilkan seperti Poin 12 di bawah), bukan cuma display:none
   di elemennya sendiri tapi juga var(--topbar-height) di-nolkan di scope
   body ini -- otomatis menghapus margin-top main.app-main & tinggi
   .chat-shell yang sebelumnya menyisakan ruang kosong bekas topbar (calc()
   yang sudah ada dipakai ulang, konsisten dengan trik --bottom-nav-height
   barusan). Satu-satunya jalan keluar jadi tombol kembali bulat di pojok
   kiri atas panel chat (lihat .chat-back-btn). */
body.crm-chat-open { --topbar-height: 0px; }
body.crm-chat-open #topbar { display: none; }

/* Poin 12: topbar collapse/mengecil saat scroll ke bawah di dalam chat,
   supaya baris pesan yang kelihatan makin banyak. Class `.crm-topbar-collapsed`
   di-toggle lewat JS berdasar posisi scroll #chat-box (cuma di mode mobile).
   Sama seperti Poin 11, di sini var(--topbar-height) di-override di scope
   body -- otomatis menyusutkan #topbar, margin-top main.app-main, DAN
   tinggi .chat-shell sekaligus lewat calc() yang sudah ada, konsisten.
   env(safe-area-inset-top) ditambahkan ke override ini (bukan ke nilai
   dasar var(--topbar-height) yang dipakai semua halaman) supaya notch/status
   bar tetap diperhitungkan HANYA saat topbar benar-benar mengecil -- di luar
   kondisi itu, tampilan halaman lain sama sekali tidak berubah. */
body.crm-topbar-collapsed {
  --topbar-height: calc(var(--topbar-collapsed-height) + env(safe-area-inset-top, 0px));
}
body.crm-topbar-collapsed #topbar {
  padding-top: env(safe-area-inset-top, 0px);
}
body.crm-topbar-collapsed .topbar-title { font-size: var(--text-sm); }
body.crm-topbar-collapsed .btn-theme span { display: none; }

/* Poin 16: kunci scroll body selagi bottom sheet (grup / "Lainnya") terbuka
   -- sheet sendiri sudah `position: fixed` dengan overflow-y sendiri, jadi
   halaman di baliknya tidak perlu (dan tidak boleh) ikut scroll bersamaan
   saat user menggeser isi sheet di HP. */
body.crm-scroll-locked { overflow: hidden; touch-action: none; }
body.crm-scroll-locked .crm-more-sheet,
body.crm-scroll-locked .group-sheet-list { touch-action: pan-y; }

/* Poin 3: sheet daftar grup untuk mulai chat baru */
.group-sheet-list { display: flex; flex-direction: column; gap: 2px; max-height: 55vh; overflow-y: auto; padding-bottom: var(--space-8px); }
.group-sheet-item {
  display: flex; align-items: center; gap: 10px;
  padding: var(--space-8px) var(--space-6px); border-radius: var(--radius-md);
  text-decoration: none; color: inherit;
  transition: background-color .12s ease;
  touch-action: manipulation;
}
.group-sheet-item:hover, .group-sheet-item:active { background-color: var(--app-surface-alt); }

.chat-list { width: 300px; flex-shrink: 0; border-right: 1px solid var(--app-border); overflow-y: auto; background-color: var(--app-surface); display: flex; flex-direction: column; }
/* Poin 1 (fix): rule lama `width: clamp(120px, 40%, 220px)` di sini datang
   SETELAH `.chat-list { width: 100% }` dari blok single-pane di atas --
   pada specificity yang sama, urutan sumber menang, jadi rule ini diam-diam
   MENIMPA BALIK lebar 100% single-pane jadi kolom sempit lagi setiap kali di
   HP. Sudah dibuang; lebar mobile sekarang murni dikontrol oleh blok
   `.chat-shell.has-active` di atas (poin 1). */

/* Toolbar dipadatkan (compact) -- sebelumnya search + filter-tabs + tombol
   "Chat Grup Baru" full-width bertumpuk 3 baris memakan ~150px+ tinggi,
   menyisakan sedikit ruang buat daftar chat di layar HP. Sekarang: search
   (1 baris) + filter-tabs & tombol grup digabung jadi 1 baris juga, padding
   dipertipis. Total tinggi toolbar turun signifikan tanpa kehilangan fungsi. */
.chat-list-toolbar { padding: var(--space-8px) var(--space-10px); border-bottom: 1px solid var(--app-border); flex-shrink: 0; display: flex; flex-direction: column; gap: 6px; }

/* Baris search + pemilih workspace -- di layar besar (>=1024px) tombol
   workspace baru ini disembunyikan (desktop sudah punya pemilihnya
   sendiri di #topbar / topbar.php, & .chat-list di sini jadi kolom
   sidebar tetap yang sempit, bukan drawer full-width, jadi tidak perlu
   dibagi 50/50), search tetap 100% seperti semula. */
.chat-search-row { display: flex; align-items: center; gap: 8px; }
.chat-search-row .chat-search { flex: 1 1 auto; min-width: 0; }
.chat-list-wa-toggle { display: none; }

/* Khusus mobile: baris search + pemilih workspace dalam satu baris
   (lihat markup .chat-search-row di chat/index.php). Dropdown workspace
   TIDAK lagi dipaksa 50% -- lebarnya sekarang mengikuti lebar natural
   kontennya (ikon+teks), PERSIS sama seperti .topbar-session-btn di
   header halaman lain (topbar.php), termasuk cap max-width:46vw yang
   sudah didefinisikan di rule dasar .topbar-session-btn (tidak di-override
   lagi di sini). Search-nya yang menyesuaikan sisa ruang lewat
   `flex: 1 1 auto` supaya selalu mengisi apa pun yang tersisa setelah
   dropdown mengambil lebar secukupnya. */
@media (max-width: 1023.98px) {
  .chat-search-row .chat-search { flex: 1 1 auto; min-width: 0; }
  .chat-list-wa-toggle {
    display: inline-flex; flex: 0 0 auto; min-width: 0;
    justify-content: flex-end;
  }
}

.chat-search {
  /* iOS UISearchBar: kapsul penuh, tanpa border, isian abu-abu tipis --
     bukan kotak bersudut dgn garis tepi. Height 32px + padding
     horizontal-only (bukan lagi padding vertikal var(--space-9px)) supaya
     tingginya PERSIS sama dengan .topbar-session-btn (dropdown workspace
     di sebelahnya, lihat .chat-search-row) yang juga height:32px. */
  display: flex; align-items: center; gap: 8px;
  background: var(--app-surface-alt); border: none; border-radius: var(--radius-full);
  height: 32px; padding: 0 var(--space-14px); color: var(--app-text-muted);
}
.chat-search input {
  border: none; background: transparent; outline: none; flex: 1; min-width: 0;
  /* Diperkecil dari 17px -> 16px (bukan var(--text-sm)/12.8px) supaya
     tampilan teks lebih proporsional terhadap kapsul search 32px, TAPI
     tetap dijaga di angka 16px persis -- di bawah itu Safari iOS
     otomatis zoom-in seluruh viewport saat search bar ini difokus
     (dipakai ulang di Chat & Kontak, jadi ini field yg sangat sering disentuh). */
  font-size: 16px; color: var(--app-text);
}
.chat-search input::placeholder { color: var(--app-text-faint); }

/* Baris kedua: filter-tabs (Semua/Pribadi/Grup) + tombol ikon "Chat Grup
   Baru" berdampingan, gantikan tombol full-width terpisah di baris ke-3
   yang lama supaya satu baris hemat ruang saja. */
.chat-toolbar-row { display: flex; align-items: center; gap: 6px; }

.chat-filter-tabs { flex: 1; display: flex; gap: 4px; background: var(--app-surface-alt); border: 1px solid var(--app-border); border-radius: var(--radius-md); padding: var(--space-3px); min-width: 0; }
.btn-filter {
  /* Compact: 34px -- masih nyaman disentuh tapi tidak lagi menghabiskan
     tinggi ekstra seperti standar 44px sebelumnya (toolbar ini sudah
     padat berdampingan dgn search + tombol grup, bukan target sentuh
     tunggal berdiri sendiri). */
  flex: 1; min-height: 34px; border: none; background: transparent; border-radius: var(--radius-md);
  padding: var(--space-4px) var(--space-6px); font-size: var(--text-xs); font-weight: 600; color: var(--app-text-muted); cursor: pointer;
  transition: all .15s; white-space: nowrap;
  touch-action: manipulation;
}
.btn-filter:hover { color: var(--app-text); }
.btn-filter.active { background: var(--app-surface); color: var(--crm-brand); box-shadow: 0 1px 2px var(--app-shadow); }

/* Tombol "Chat Grup Baru" -- versi ikon-saja, sejajar dgn filter-tabs,
   tinggi disamakan (34px) supaya rapi satu baris. */
.chat-newgroup-btn {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 34px; height: 34px; min-width: 34px;
  border-radius: var(--radius-md);
  border: 1px solid var(--app-border); background: var(--app-surface-alt);
  color: var(--app-text-muted); cursor: pointer; transition: all .15s;
  touch-action: manipulation;
}
.chat-newgroup-btn:hover { color: var(--app-text); background: var(--app-hover); }
.chat-newgroup-btn .icon { margin: 0; }

.chat-list-items { overflow-y: auto; flex: 1; position: relative; }

.chat-list-item {
  display: flex; align-items: center; gap: 12px;
  padding: var(--space-11px) var(--space-14px);
  /* WhatsApp: baris daftar chat TIDAK punya garis pembatas -- pemisah
     visual murni datang dari spasi + avatar besar, bukan hairline.
     border dihapus (sebelumnya border-bottom 1px var(--app-border)). */
  text-decoration: none; color: inherit;
  transition: background-color .12s ease;
  /* Poin 14: hilangkan delay ~300ms & zoom aksidental saat tap cepat/ganda
     pada item daftar chat. */
  touch-action: manipulation;
}
/* Bug fix: `display: flex` di atas sama spesifisitasnya dengan
   `.hidden{display:none}` bawaan Tailwind (satu class lawan satu class),
   dan karena app.css dimuat SETELAH tailwind.css, flex di atas yang menang
   cascade -- akibatnya class `hidden` yang di-toggle applyChatFilters()
   (tab Semua/Pribadi/Grup + filter status pipeline + pencarian) tidak
   pernah benar-benar menyembunyikan item, jadi tab filter terlihat
   "tidak bekerja" padahal JS-nya sudah benar menghitung & menandai item
   yang harus disembunyikan. Sama pola dengan fix .chat-pipeline-menu.hidden. */
.chat-list-item.hidden { display: none; }
.chat-list-item:hover { background-color: var(--app-surface-alt); }
/* Poin 17: :hover tidak ada gunanya di touchscreen (malah bisa "nyangkut"
   aktif setelah tap di sebagian browser mobile) -- tambahkan :active supaya
   ada umpan balik visual instan saat disentuh, terlepas dari device. */
.chat-list-item:active { background-color: var(--app-surface-alt); }
.chat-list-item.active { background-color: rgb(var(--crm-brand-rgb) / .1); }
.chat-list-item-text { min-width: 0; flex: 1; }
.chat-list-item .chat-number { font-weight: 600; font-size: var(--text-sm); display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--app-text); }
.chat-list-item .chat-preview { color: var(--app-text-muted); font-size: var(--text-xs); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-group-tag { opacity: .6; margin-right: 2px; }

/* Poin 7: kolom kanan daftar chat -- waktu relatif + badge unread,
   ditumpuk vertikal ala WhatsApp (waktu di atas, badge di bawahnya). */
.chat-list-item-meta {
  flex-shrink: 0; display: flex; flex-direction: column; align-items: flex-end;
  gap: 4px; align-self: stretch; justify-content: center;
}
.chat-list-time { font-size: var(--text-2xs); color: var(--app-text-muted); white-space: nowrap; }
.chat-unread-badge {
  min-width: 20px; height: 20px; padding: 0 var(--space-6px); border-radius: 999px;
  background: var(--crm-brand); color: #fff; font-size: .6875rem; font-weight: 700;
  line-height: 20px; text-align: center;
}
/* Chat dengan pesan belum dibaca ditonjolkan sedikit -- nama lebih tegas,
   pratinjau lebih gelap (bukan cuma abu-abu muted) supaya gampang dipindai. */
.chat-list-item.has-unread .chat-number { color: var(--app-text); }
.chat-list-item.has-unread .chat-preview { color: var(--app-text); font-weight: 500; }
.chat-list-item.has-unread .chat-list-time { color: var(--crm-brand); font-weight: 700; }

/* Tombol mengambang "mulai chat baru" -- pengganti tombol ikon yang dulu
   nempel di toolbar. Posisi & ukurannya mengikuti pola compose button
   WhatsApp: kapsul bundar, warna brand, melayang di pojok kanan bawah
   daftar chat, di atas bottom-nav mobile. */
.chat-fab {
  position: absolute; right: 16px; bottom: 16px; z-index: 5;
  width: 52px; height: 52px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--crm-brand); color: #fff; border: none;
  box-shadow: var(--shadow-md);
  cursor: pointer; transition: background-color .15s ease, transform .1s ease;
  touch-action: manipulation;
}
.chat-fab:hover { background: var(--crm-brand-hover); }
.chat-fab:active { transform: scale(.94); }
.chat-fab .icon { margin: 0; width: 22px; height: 22px; }
/* Di mobile single-pane, list mengisi lebar penuh & bottom-nav tetap
   tampil di bawahnya -- naikkan FAB supaya tidak ketutup bottom-nav. */
@media (max-width: 767.98px) {
  .chat-fab { bottom: calc(16px + var(--bottom-nav-height)); }
}

.chat-avatar {
  flex-shrink: 0; width: 50px; height: 50px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--text-sm); font-weight: 700; color: #fff;
}
/* Palet avatar memakai warna sistem Apple resmi (systemTeal/orange/purple/
   pink/green) -- persis pola Contacts.app/Messages.app yang memberi tiap
   orang warna berbeda, tapi semuanya tetap dari satu keluarga warna iOS,
   bukan warna acak di luar HIG. */
.avatar-c1 { background: var(--crm-brand); }
.avatar-c2 { background: var(--crm-avatar-c2); }
.avatar-c3 { background: var(--crm-avatar-c3); }
.avatar-c4 { background: var(--crm-avatar-c4); }
.avatar-c5 { background: var(--crm-avatar-c5); }
.avatar-c6 { background: var(--crm-avatar-c6); }

/* Poin 4: avatar mini di samping bubble grup masuk */
.chat-avatar-sm { width: 24px; height: 24px; font-size: .625rem; margin-bottom: 2px; }

/* Poin 4: warna nama pengirim di bubble grup, konsisten per orang -- pakai
   indeks warna yang sama dengan avatar-cN (chat_color_index()) tapi di sini
   sebagai warna TEKS, bukan background, supaya tidak numpuk sama avatar. */
.chat-sender-name.sender-c1 { color: var(--crm-brand); }
.chat-sender-name.sender-c2 { color: var(--crm-sender-c2); }
.chat-sender-name.sender-c3 { color: var(--crm-sender-c3); }
.chat-sender-name.sender-c4 { color: var(--crm-sender-c4); }
.chat-sender-name.sender-c5 { color: var(--crm-sender-c5); }
.chat-sender-name.sender-c6 { color: var(--crm-sender-c6); }
.chat-bubble.out .chat-sender-name { color: #d7fff0 !important; }

.chat-panel { flex: 1; display: flex; flex-direction: column; min-width: 0; }
/* Header panel chat = nav bar iOS: frosted glass tipis, judul (avatar +
   nama) di tengah, tombol kembali & poll-dot di kedua sisi -- persis pola
   Messages.app saat sebuah percakapan terbuka. */
.chat-panel-header {
  position: relative; z-index: 2;
  padding: var(--space-8px) var(--space-12px);
  background: var(--crm-glass-bg);
  -webkit-backdrop-filter: var(--crm-glass-blur);
  backdrop-filter: var(--crm-glass-blur);
  border-bottom: 0.5px solid var(--crm-glass-border);
  color: var(--app-text);
}
.chat-panel-header-center {
  flex: 1; min-width: 0; display: flex; align-items: center; justify-content: center; gap: 6px;
}
.chat-panel-avatar { width: 26px; height: 26px; font-size: .6rem; }
.chat-panel-header-title {
  font-size: var(--text-sm); font-weight: 600; letter-spacing: -0.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chat-back-btn {
  /* Poin 8: 44x44px -- sebelumnya 30x30px, di bawah standar area sentuh. */
  display: none; align-items: center; justify-content: center;
  width: 44px; height: 44px; min-width: 44px; min-height: 44px;
  /* Poin 17: bentuk lingkaran (bukan kotak radius-md) -- karena #topbar
     situs sudah disembunyikan total saat chat terbuka (lihat Poin 11/17
     di atas), tombol ini jadi satu-satunya elemen navigasi yang mengambang
     di pojok kiri atas panel chat, jadi wujudnya dibuat menonjol seperti
     tombol kembali fullscreen ala galeri foto / video call. */
  border-radius: var(--radius-full);
  color: var(--app-text-muted); background: var(--app-surface-alt); border: 1px solid var(--app-border);
  flex-shrink: 0; margin: -4px 0; /* imbangi tinggi header supaya tidak menggembung */
  /* Poin 14: satu-satunya jalan keluar dari chat di mobile (bottom-nav
     disembunyikan saat chat terbuka, lihat Poin 11) -- tap harus responsif. */
  touch-action: manipulation;
  /* Dipakai juga sebagai <a href="/chat"> (tombol kembali di header chat
     aktif, lihat #chatDrawerToggle) -- reset underline bawaan anchor,
     bukan cuma <button> lagi. */
  text-decoration: none;
}
.chat-back-btn:hover { color: var(--app-text); background: var(--app-hover); }
.chat-back-btn .icon { width: 20px; height: 20px; }

/* Poin 6: titik kecil di header yang "berdenyut" tiap kali polling jalan --
   dibungkus .chat-back-btn-spacer (lihat di bawah) supaya sisi kanan header
   punya lebar sama dengan tombol hamburger di kiri, menjaga identitas di
   tengah tetap center sekarang tombol "+" sudah dihapus dari header. */
.chat-poll-dot {
  width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0;
  background: var(--app-text-faint); opacity: .4;
  transition: opacity .25s ease, background-color .25s ease, transform .25s ease;
}
/* Spacer selebar 44px (sama dengan .chat-back-btn) dipakai di dua tempat:
   topbar empty-state (pengganti tombol "+" yang dihapus, biar judul tetap
   center) dan header chat aktif (pembungkus poll-dot, biar identitas
   tengah tetap center). Transparan & tidak menangkap klik. */
.chat-back-btn-spacer {
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; min-width: 44px; min-height: 44px;
  flex-shrink: 0; pointer-events: none;
}
.chat-poll-dot.is-active { background: var(--crm-brand); opacity: 1; transform: scale(1.3); }

/* ── Fitur 1: chip tag di header chat ── */
.chat-panel-header-wrap { position: relative; z-index: 2; }
.chat-header-identity-btn {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  flex: 1; min-width: 0; background: none; border: none; padding: 4px 2px; margin: 0;
  color: inherit; cursor: pointer; touch-action: manipulation;
}
.chat-header-swipe-hint { color: var(--app-text-faint); opacity: .7; }
.chat-tag-row {
  display: flex; align-items: center; gap: 8px;
  padding: 0 var(--space-12px) var(--space-8px);
  background: var(--crm-glass-bg);
  -webkit-backdrop-filter: var(--crm-glass-blur);
  backdrop-filter: var(--crm-glass-blur);
  border-bottom: 0.5px solid var(--crm-glass-border);
}
.chat-tag-chips { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; overflow-x: auto; scrollbar-width: none; }
.chat-tag-chips::-webkit-scrollbar { display: none; }
.chat-tag-chip { flex-shrink: 0; }
/* Bug fix: sebelumnya .chat-tag-chip mewarisi padding tipis dari
   .tag-chip-sm (1px atas-bawah) yang dipakai bareng dg badge kecil di
   halaman Kontak. Di header chat, chip ini sejajar dg .chat-pipeline-pill
   (4px atas-bawah) -- beda 3px/sisi bikin baris "Premium/Tag" kelihatan
   gepeng dibanding pill "Prospek Baru" di bawahnya. Override di sini saja
   (bukan ubah .tag-chip-sm global) supaya halaman Kontak tidak ikut berubah. */
.chat-tag-chip { padding: var(--space-4px) var(--space-10px); }
.chat-tag-chip-remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; margin-left: 1px; padding: 0; border: none; border-radius: 50%;
  background: color-mix(in srgb, var(--tag-color) 22%, transparent); color: var(--tag-color);
  flex-shrink: 0; cursor: pointer; touch-action: manipulation;
}
/* Bug fix: sebelumnya pakai karakter "&times;" di font-size .85rem --
   glyph "×" bawaan font TIDAK benar-benar center secara vertikal (bobot
   visualnya condong ke atas baseline), jadi di lingkaran sekecil ini
   kelihatan mepet/miring ke satu sisi (lihat laporan bug: "dot dan x nya
   tidak proper"). SVG silang presisi ini selalu center sempurna, sama
   gaya dengan ikon-ikon lain di app (stroke=currentColor, ikut warna tag). */
.chat-tag-chip-remove svg { width: 8px; height: 8px; display: block; }
.chat-tag-chip-remove:hover { background: color-mix(in srgb, var(--tag-color) 38%, transparent); }
.chat-tag-empty { font-size: var(--text-xs); color: var(--app-text-faint); font-style: italic; }
.chat-tag-add-btn {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 4px;
  /* Bug fix: dulu var(--space-1px) var(--space-8px) -- terlalu tipis
     dibanding .chat-pipeline-pill (4px/10px), lihat catatan di .chat-tag-chip
     di atas. Disamakan supaya baris "Premium/Tag" & "Prospek Baru" senada. */
  padding: var(--space-4px) var(--space-10px); border-radius: 999px; font-size: var(--text-xs); font-weight: 600;
  background: var(--app-surface-alt); border: 1px solid var(--app-border); color: var(--app-text-muted);
  cursor: pointer; touch-action: manipulation;
}
.chat-tag-add-btn:hover { color: var(--app-text); border-color: var(--app-text-faint); }
.chat-tag-add-btn .icon { width: 0.75rem; height: 0.75rem; }
.chat-tag-add-disabled {
  flex-shrink: 0; font-size: var(--text-xs); color: var(--app-text-faint); font-style: italic; white-space: nowrap;
}
.chat-tag-menu { max-height: 260px; overflow-y: auto; }
.btn-chat-tag-toggle { width: 100%; gap: 8px; text-align: left; background: none; border: none; cursor: pointer; }
.chat-tag-menu-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-tag-menu-check { flex-shrink: 0; width: 16px; height: 16px; opacity: 0; color: var(--crm-brand); }
.btn-chat-tag-toggle.is-checked .chat-tag-menu-check { opacity: 1; }
.btn-chat-tag-toggle.is-disabled { opacity: .5; pointer-events: none; }

/* ── Fitur 2: kartu mini-profil (swipe-up dari header chat) ── */
.chat-profile-sheet { max-height: 78vh; }
.chat-profile-body .crm-row-value { color: var(--app-text-muted); font-size: var(--text-sm); }
.chat-profile-section-title { font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .02em; color: var(--app-text-faint); margin: 4px 2px 6px; }
.chat-profile-tag-row { gap: 8px; }
.chat-profile-tag-name { flex: 1; min-width: 0; font-weight: 600; color: var(--app-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-profile-tag-date { flex-shrink: 0; font-size: var(--text-xs); color: var(--app-text-muted); }
.chat-profile-footnote { margin: 14px 2px 0; font-size: var(--text-xs); color: var(--app-text-faint); }
.chat-profile-loading { padding: 24px 0; text-align: center; color: var(--app-text-muted); font-size: var(--text-sm); }
/* #groupSheet sudah di-override tampil di desktop (lihat blok di atas) --
   sheet mini-profil chat juga dipakai lewat tap (bukan cuma swipe murni
   touch), jadi sama-sama harus tetap terlihat di layar lebar. */
@media (min-width: 1024px) {
  #chatProfileBackdrop, #chatProfileSheet { display: block !important; }
}

/* ── Fitur 4: filter status pipeline di sidebar daftar chat ── */
.chat-status-filter-tabs {
  display: flex; gap: 6px; overflow-x: auto; scrollbar-width: none; padding: 2px 0 0;
}
.chat-status-filter-tabs::-webkit-scrollbar { display: none; }
.btn-status-filter {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  padding: var(--space-4px) var(--space-8px); border-radius: 999px; font-size: var(--text-2xs); font-weight: 600;
  background: var(--app-surface-alt); border: 1px solid var(--app-border); color: var(--app-text-muted);
  cursor: pointer; touch-action: manipulation; transition: all .15s;
}
.btn-status-filter .status-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--status-color, var(--app-text-faint)); flex-shrink: 0;
}
.btn-status-filter[data-status-filter="all"] .status-dot { display: none; }
.btn-status-filter.active {
  background: color-mix(in srgb, var(--status-color, var(--crm-brand)) 14%, var(--app-surface));
  border-color: var(--status-color, var(--crm-brand));
  color: var(--app-text);
}
.btn-status-filter[data-status-filter="all"].active { color: var(--crm-brand); border-color: var(--crm-brand); }

/* Titik status pipeline kecil di daftar chat (di bawah waktu relatif) */
.chat-list-status-dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--status-color, var(--app-text-faint));
  align-self: flex-end; margin-top: 1px;
}

/* ── Fitur 4: pill status pipeline di header chat (segmented control) ── */
.chat-pipeline-row {
  display: flex; align-items: center; padding: var(--space-8px) var(--space-12px) 0;
}
.chat-pipeline-pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: var(--space-4px) var(--space-10px); border-radius: 999px; font-size: var(--text-xs); font-weight: 600;
  background: color-mix(in srgb, var(--status-color) 14%, var(--app-surface-alt));
  border: 1px solid var(--status-color); color: var(--app-text);
  cursor: pointer; touch-action: manipulation;
}
.chat-pipeline-pill .status-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--status-color); flex-shrink: 0; }
.chat-pipeline-pill .icon { width: 0.7rem; height: 0.7rem; opacity: .6; }
.chat-pipeline-menu {
  min-width: 160px; padding: var(--space-4px); display: flex; flex-direction: column; gap: 2px;
}
/* Bug fix: `display: flex` di atas punya spesifisitas yang sama dengan
   `.hidden{display:none}` bawaan Tailwind (satu class lawan satu class),
   dan karena app.css dimuat SETELAH tailwind.css, aturan flex di atas yang
   menang urutan cascade -- akibatnya class `hidden` yang dipasang/dilepas
   JS (lihat chatPipelineMenu di chat/index.php) tidak pernah benar-benar
   menyembunyikan menu, jadi dropdown status pipeline terlihat selalu
   terbuka. Override eksplisit di sini (2 class = spesifisitas lebih
   tinggi) memastikan `hidden` selalu menang, apa pun urutan file CSS-nya. */
.chat-pipeline-menu.hidden { display: none; }
.btn-pipeline-option {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  padding: var(--space-6px) var(--space-10px); border-radius: var(--radius-sm); border: none; background: none;
  font-size: var(--text-sm); color: var(--app-text); cursor: pointer; touch-action: manipulation;
}
.btn-pipeline-option::before {
  content: ''; width: 8px; height: 8px; border-radius: 50%; background: var(--status-color); flex-shrink: 0;
}
.btn-pipeline-option:hover { background: var(--app-hover); }
.btn-pipeline-option.is-active { background: color-mix(in srgb, var(--status-color) 16%, transparent); font-weight: 700; }
.btn-pipeline-option.is-disabled { opacity: .5; pointer-events: none; }

/* ── Fitur 3: sticky note admin -- diselipkan di antara bubble chat ── */
.chat-sticky-note {
  margin: 4px auto 10px; max-width: 88%;
  background: var(--crm-note-bg, #fff6cc); border: 1px solid var(--crm-note-border, #e8d27a);
  border-radius: var(--radius-md); padding: var(--space-8px) var(--space-10px);
  box-shadow: var(--shadow-sm);
}
.chat-sticky-note-head {
  display: flex; align-items: center; gap: 5px; margin-bottom: 3px;
  color: var(--crm-note-text, #7a5f00); opacity: .85;
}
.chat-sticky-note-head .icon { width: 0.75rem; height: 0.75rem; flex-shrink: 0; }
.chat-sticky-note-admin { font-size: var(--text-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: .02em; }
.chat-sticky-note-time { font-size: var(--text-2xs); margin-left: auto; }
.chat-sticky-note-delete {
  display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; padding: 0;
  border: none; border-radius: 50%; background: color-mix(in srgb, var(--crm-note-text, #7a5f00) 16%, transparent);
  color: var(--crm-note-text, #7a5f00); font-size: .8rem; line-height: 1; cursor: pointer; touch-action: manipulation;
}
.chat-sticky-note-text { font-size: var(--text-sm); color: #4a3b00; word-break: break-word; white-space: pre-wrap; }
[data-bs-theme="dark"] .chat-sticky-note {
  --crm-note-bg: #3a3210; --crm-note-border: #6b5b1a; --crm-note-text: #e8d27a;
}
[data-bs-theme="dark"] .chat-sticky-note-text { color: #f0e2a3; }
[data-bs-theme="dark"] .chat-note-composer {
  --crm-note-bg: #3a3210; --crm-note-border: #6b5b1a; --crm-note-text: #e8d27a;
}

/* ── Fitur 3: panel tulis catatan internal (di atas composer) ── */
.chat-note-composer {
  margin: 0 var(--space-12px) var(--space-8px); padding: var(--space-8px) var(--space-10px);
  background: var(--crm-note-bg, #fff6cc); border: 1px solid var(--crm-note-border, #e8d27a);
  border-radius: var(--radius-md);
}
.chat-note-composer-head {
  display: flex; align-items: center; gap: 5px; font-size: var(--text-2xs); font-weight: 700;
  color: var(--crm-note-text, #7a5f00); text-transform: uppercase; letter-spacing: .02em; margin-bottom: 5px;
}
.chat-note-composer-head .icon { width: 0.7rem; height: 0.7rem; }
.chat-note-textarea {
  width: 100%; resize: none; border: 1px solid var(--crm-note-border, #e8d27a); border-radius: var(--radius-sm);
  background: var(--app-surface); color: var(--app-text); font-size: var(--text-sm); padding: var(--space-6px) var(--space-8px);
  outline: none;
}
.chat-note-textarea:focus { border-color: var(--crm-brand); }
.chat-note-composer-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 6px; }
.btn-note-cancel, .btn-note-save {
  padding: var(--space-4px) var(--space-12px); border-radius: 999px; font-size: var(--text-xs); font-weight: 600;
  cursor: pointer; touch-action: manipulation; border: 1px solid transparent;
}
.btn-note-cancel { background: transparent; color: var(--app-text-muted); border-color: var(--app-border); }
.btn-note-save { background: var(--crm-note-text, #7a5f00); color: #fff; }
.btn-note-save:disabled { opacity: .6; pointer-events: none; }
.chat-note-toggle-btn { color: var(--app-text-muted); }
.chat-note-toggle-btn:hover { color: var(--crm-note-text, #7a5f00); }

/* Wrapper relatif supaya tombol "scroll ke bawah" bisa melayang di atas #chat-box */
.chat-box-wrap { position: relative; flex: 1; min-height: 0; display: flex; }

#chat-box {
  background-color: var(--app-chat-bg);
  background-image: radial-gradient(var(--app-chat-pattern) 1px, transparent 1px);
  background-size: 16px 16px;
  flex: 1; overflow-y: auto; padding: var(--space-16px);
  /* Poin 13: cegah scroll pesan "bocor" ke body dan memicu pull-to-refresh
     / rubber-band bounce browser mobile saat sudah mentok atas/bawah. */
  overscroll-behavior: contain;
}

/* Poin 4: separator tanggal di antara bubble ("Hari ini" / "Kemarin" / tgl) */
.chat-date-separator { display: flex; justify-content: center; margin: 10px 0 14px; }
.chat-date-separator span {
  background: var(--app-surface); color: var(--app-text-muted);
  font-size: var(--text-xs); font-weight: 600; padding: var(--space-4px) var(--space-12px);
  border-radius: var(--radius-md); box-shadow: var(--shadow-sm); border: 1px solid var(--app-border);
}

.chat-bubble-row { display: flex; align-items: flex-end; gap: 6px; margin-bottom: 8px; }
.chat-bubble-row.out { justify-content: flex-end; }
.chat-bubble {
  max-width: 72%; padding: .5rem .75rem; border-radius: var(--radius-md);
  font-size: var(--text-sm); box-shadow: var(--shadow-sm); word-break: break-word;
  user-select: text; -webkit-user-select: text;
  /* Poin 15: long-press pada bubble sudah dipegang JS (triggerCopyBubble) --
     tanpa ini, iOS Safari akan menampilkan menu native "Copy/Share/Look Up"
     sendiri di atas toast kustom kita saat long-press, jadi tumpang tindih
     dua mekanisme copy sekaligus. */
  -webkit-touch-callout: none;
  transition: background-color .15s ease, filter .15s ease;
}
.chat-bubble.in { background-color: var(--app-surface); border: 1px solid var(--app-border); border-bottom-left-radius: var(--radius-xs); color: var(--app-text); }
.chat-bubble.out { background-color: var(--crm-brand); color: #fff; border-bottom-right-radius: var(--radius-xs); }
.chat-bubble .chat-time { font-size: .6875rem; opacity: .7; margin-top: .15rem; }
.chat-bubble.out .text-success { color: #d7fff0 !important; }
/* Poin 4: kedipan singkat saat long-press berhasil copy teks */
.chat-bubble.chat-bubble-copied { filter: brightness(.92); }

/* Poin 4: toast kecil "Teks disalin" saat long-press copy */
.chat-copy-toast {
  position: fixed; left: 50%; bottom: calc(var(--bottom-nav-height, 0px) + 24px + env(safe-area-inset-bottom, 0px));
  transform: translate(-50%, 8px); background: var(--app-text); color: var(--app-surface);
  font-size: var(--text-xs); font-weight: 600; padding: var(--space-7px) var(--space-14px); border-radius: 999px;
  box-shadow: var(--shadow-md, 0 4px 12px rgba(0,0,0,.2)); opacity: 0; pointer-events: none;
  transition: opacity .18s ease, transform .18s ease; z-index: 1080;
}
.chat-copy-toast.is-visible { opacity: 1; transform: translate(-50%, 0); }

/* Poin 4: tombol melayang "scroll ke pesan terbaru" */
.chat-scroll-bottom-btn {
  /* Poin 8: 44x44px area sentuh (dulu width/height 40px konflik dengan
     min-width/min-height 44px -- dirapikan jadi satu ukuran yang jelas). */
  position: absolute; right: 16px; bottom: 16px; z-index: 5;
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; border: 0.5px solid var(--crm-glass-border);
  background: var(--crm-glass-bg); color: var(--app-text);
  -webkit-backdrop-filter: var(--crm-glass-blur);
  backdrop-filter: var(--crm-glass-blur);
  box-shadow: var(--shadow-md, 0 4px 10px rgba(0,0,0,.18));
  cursor: pointer; transition: transform .15s ease, background-color .15s ease;
  touch-action: manipulation;
}
.chat-scroll-bottom-btn:hover { background: var(--app-surface-alt); }
.chat-scroll-bottom-btn:active { transform: scale(.94); }
/* Bug fix: pola sama dengan .chat-pipeline-menu.hidden & .chat-list-item.hidden
   di atas -- `display: flex` pada .chat-scroll-bottom-btn menang cascade
   lawan `.hidden{display:none}` Tailwind, jadi show/hide tombol ini via JS
   (scrollBtn.classList.add/remove('hidden')) tidak pernah benar2 berefek. */
.chat-scroll-bottom-btn.hidden { display: none; }
.chat-scroll-bottom-badge {
  position: absolute; top: -4px; right: -4px; min-width: 18px; height: 18px;
  padding: 0 var(--space-4px); border-radius: 999px; background: var(--crm-brand); color: #fff;
  font-size: .625rem; font-weight: 700; line-height: 18px; text-align: center;
  box-shadow: 0 0 0 2px var(--app-surface);
}

.chat-composer {
  border-top: 1px solid var(--app-border); padding: var(--space-12px); background-color: var(--app-surface);
  padding-bottom: calc(var(--space-12px) + env(safe-area-inset-bottom, 0px));
}
/* Poin 5: textarea auto-grow menggantikan input satu baris -- mendukung
   pesan multi-baris tanpa mengubah tinggi composer secara tiba-tiba. */
.chat-textarea {
  flex: 1; resize: none; overflow-y: auto; min-height: 38px; max-height: 120px;
  line-height: 1.35; padding-top: .5rem; padding-bottom: .5rem;
  /* !important: markup memakai utility Tailwind "text-base" (14px, lihat
     chat/index.php) yang bisa menang cascade tergantung urutan load Tailwind
     CDN vs app.css -- dipaksa 17px supaya PASTI di atas ambang 16px dan
     Safari iOS tidak auto-zoom saat kotak ketik pesan ini difokus (field
     paling sering disentuh di seluruh app). */
  font-size: 17px !important;
}
.chat-composer .btn-icon-only {
  flex-shrink: 0; width: 44px; height: 44px; min-width: 44px; min-height: 44px;
  display: flex; align-items: center; justify-content: center; position: relative;
  /* Poin 14: tombol kirim sering di-tap cepat berurutan -- hilangkan delay
     300ms & cegah zoom aksidental di tap ganda. */
  touch-action: manipulation;
}
/* Poin 5: spinner kecil di tombol kirim saat proses pengiriman berlangsung */
.chat-send-spinner {
  width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,.4); border-top-color: #fff;
  animation: chat-send-spin .7s linear infinite;
}
@keyframes chat-send-spin { to { transform: rotate(360deg); } }

/* Bug fix (UX): sebelumnya justify-content:center bikin ikon+teks
   "Pilih percakapan untuk mulai membalas" jatuh persis di tengah tinggi
   panel -- di layar HP terasa terlalu turun/kosong di bagian atas.
   Dipindah lebih ke atas: flex-start + padding-top proporsional (dibatasi
   max supaya tidak berlebihan di layar tinggi). */
.chat-empty { flex: 1; display: flex; align-items: center; justify-content: flex-start; flex-direction: column; gap: 8px; color: var(--app-text-muted); background-color: var(--app-chat-bg); text-align: center; padding: var(--space-20px); padding-top: min(14vh, 120px); }

/* Poin 9: empty state daftar chat -- ilustrasi + copy + CTA, bukan cuma
   satu baris teks kecil pojok kiri atas yang mudah kelewat. */
.chat-list-empty {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: var(--space-32px) var(--space-20px); color: var(--app-text-muted);
}
.chat-list-empty .icon { color: var(--app-text-faint); margin-bottom: 4px; }
/* Bug fix: pola sama seperti fix .hidden lain di file ini -- display:flex
   di atas menang cascade lawan .hidden Tailwind, jadi
   chatListEmpty.classList.toggle('hidden', ...) tidak berefek. */
.chat-list-empty.hidden { display: none; }
.chat-list-empty-title { color: var(--app-text); font-weight: 600; font-size: var(--text-md); }
.chat-list-empty-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }

/* Poin 9: skeleton loader berkedip (shimmer) untuk konten yang dimuat lewat
   AJAX -- dipakai saat daftar grup diambil dari WhatsApp di bottom sheet,
   supaya terasa "sedang memuat" daripada blank/teks statis. */
.chat-skeleton-row { display: flex; align-items: center; gap: 10px; padding: var(--space-8px) var(--space-6px); }
.chat-skeleton {
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg, var(--app-surface-alt) 25%, var(--app-border) 37%, var(--app-surface-alt) 63%);
  background-size: 400% 100%;
  animation: chat-skeleton-shimmer 1.4s ease infinite;
}
.chat-skeleton-avatar { flex-shrink: 0; width: 38px; height: 38px; border-radius: 50%; }
.chat-skeleton-line { flex: 1; height: 14px; max-width: 70%; }
@keyframes chat-skeleton-shimmer {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}
@media (prefers-reduced-motion: reduce) {
  .chat-skeleton { animation: none; background: var(--app-surface-alt); }
}

/* ---------------------------------------------------------------------
 * Session / QR connect
 * ------------------------------------------------------------------- */
.connect-card { max-width: 420px; margin-inline: auto; }
.qr-frame { width: 100%; max-width: 220px; margin-inline: auto; border: 1px solid var(--app-border); border-radius: var(--radius-md); padding: var(--space-14px); background-color: var(--qr-surface); box-shadow: var(--shadow-sm); }
.pairing-code-display {
  font-size: clamp(1.7rem, 7vw, 2.1rem); font-weight: 700; letter-spacing: .3em; padding-left: .3em;
  color: var(--app-text); font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------
 * iOS Alert / Confirm -- pengganti window.confirm()/window.alert() bawaan
 * browser. Lihat public/assets/js/ui.js untuk logic (window.iosAlert /
 * window.iosConfirm / auto-intercept <form data-confirm="...">). Meniru
 * UIAlertController: kartu kecil terpusat, frosted glass, tombol
 * horizontal dipisah separator tipis.
 * ------------------------------------------------------------------- */
.crm-alert-backdrop {
  position: fixed; inset: 0; z-index: 1090;
  background: rgba(0,0,0,0.28);
  display: flex; align-items: center; justify-content: center; padding: var(--space-24px);
  opacity: 0; transition: opacity .15s ease;
}
.crm-alert-backdrop.is-visible { opacity: 1; }
.crm-alert-card {
  width: 100%; max-width: 270px;
  background: var(--crm-glass-bg);
  -webkit-backdrop-filter: var(--crm-glass-blur);
  backdrop-filter: var(--crm-glass-blur);
  border: 1px solid var(--crm-glass-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
  transform: scale(.92); transition: transform .15s ease;
  text-align: center;
}
.crm-alert-backdrop.is-visible .crm-alert-card { transform: scale(1); }
.crm-alert-body { padding: var(--space-19px) var(--space-16px) var(--space-17px); }
.crm-alert-title { font-size: var(--text-md); font-weight: 600; color: var(--app-text); line-height: 1.3; }
.crm-alert-message { font-size: var(--text-sm); color: var(--app-text-muted); line-height: 1.4; margin-top: 4px; }
.crm-alert-title:only-child { margin-top: 2px; }
.crm-alert-actions {
  display: flex; border-top: 1px solid var(--app-border);
}
.crm-alert-actions.is-stacked { flex-direction: column; }
.crm-alert-btn {
  flex: 1; min-height: 44px; padding: 0 var(--space-10px); border: none; background: transparent;
  font-family: inherit; font-size: var(--text-md); font-weight: 400; color: var(--crm-brand);
  cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: background-color .1s ease;
}
.crm-alert-btn:active { background: var(--app-hover); }
.crm-alert-btn + .crm-alert-btn { border-left: 1px solid var(--app-border); }
.crm-alert-actions.is-stacked .crm-alert-btn + .crm-alert-btn { border-left: none; border-top: 1px solid var(--app-border); }
.crm-alert-btn.is-cancel { font-weight: 600; }
.crm-alert-btn.is-primary { font-weight: 600; }
.crm-alert-btn.is-destructive { color: var(--crm-color-danger); font-weight: 600; }

/* ---------------------------------------------------------------------
 * Session / Pengaturan Sesi -- iOS Settings-style layout khusus halaman
 * ini (kartu tunggal terpusat, avatar besar, list group).
 * ------------------------------------------------------------------- */
.crm-session-avatar {
  width: 64px; height: 64px; border-radius: 50%; margin: 4px auto 10px;
  display: flex; align-items: center; justify-content: center;
  background: var(--crm-brand); color: #fff; font-weight: 700; font-size: 1.35rem;
  letter-spacing: 0;
}
.crm-session-avatar.is-neutral { background: var(--app-text-faint); }

/* =====================================================================
 * Branding: logo custom (sidebar/login) + card Identitas Aplikasi +
 * color picker custom (bukan <input type="color"> native) di halaman
 * Pengaturan -- lihat resources/views/settings/index.php.
 * ===================================================================== */
.sidebar-logo-img { width: 24px; height: 24px; object-fit: contain; border-radius: 6px; flex-shrink: 0; }
.auth-brand-logo-img { width: 1.4rem; height: 1.4rem; object-fit: contain; border-radius: 6px; }

.branding-preview-box {
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex-shrink: 0;
  border-radius: 9px; border: 1px solid var(--app-border);
  background: var(--app-surface-alt); overflow: hidden;
}
.branding-preview-box img { width: 100%; height: 100%; object-fit: contain; }
.branding-preview-box .icon { color: var(--app-text-faint); }

/* --- Color picker custom --------------------------------------------- */
.color-field-row { display: flex; align-items: center; gap: 10px; }
.color-swatch-btn {
  width: 40px; height: 40px; flex-shrink: 0; border-radius: 9px;
  border: 1px solid var(--app-border); cursor: pointer; padding: 0;
  box-shadow: var(--shadow-sm); touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.color-swatch-btn:focus-visible { outline: 2px solid var(--crm-brand); outline-offset: 2px; }

.color-picker-panel {
  margin-top: 12px; padding: var(--space-14px); border-radius: 9px;
  background: var(--app-surface-alt); border: 1px solid var(--app-border);
}
.color-picker-panel.hidden { display: none; }

.color-sv-wrap { position: relative; width: 100%; border-radius: 9px; overflow: hidden; touch-action: none; }
.color-sv-wrap canvas { display: block; width: 100%; height: 140px; cursor: crosshair; }
.color-sv-cursor {
  position: absolute; width: 16px; height: 16px; margin: -8px 0 0 -8px;
  border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px rgba(0,0,0,.35), 0 1px 3px rgba(0,0,0,.4);
  pointer-events: none; top: 0; left: 0;
}

.color-hue-wrap { position: relative; margin-top: 12px; height: 18px; }
.color-hue-slider {
  -webkit-appearance: none; appearance: none; width: 100%; height: 12px; margin: 3px 0;
  border-radius: 999px; cursor: pointer; outline: none;
  background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
}
.color-hue-slider::-webkit-slider-thumb {
  -webkit-appearance: none; width: 20px; height: 20px; border-radius: 50%;
  background: #fff; border: 2px solid rgba(0,0,0,.25); box-shadow: 0 1px 3px rgba(0,0,0,.3); cursor: pointer;
}
.color-hue-slider::-moz-range-thumb {
  width: 20px; height: 20px; border-radius: 50%; background: #fff;
  border: 2px solid rgba(0,0,0,.25); box-shadow: 0 1px 3px rgba(0,0,0,.3); cursor: pointer;
}

.color-presets { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.color-preset-swatch {
  width: 26px; height: 26px; border-radius: 50%; border: 1px solid var(--app-border);
  cursor: pointer; padding: 0; box-shadow: var(--shadow-sm); flex-shrink: 0;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.color-preset-swatch:hover { transform: scale(1.08); }
.color-preset-swatch.is-active { outline: 2px solid var(--crm-brand); outline-offset: 2px; }

/* Label section di halaman Pengaturan (mengelompokkan kartu: Status Sistem,
   Identitas Aplikasi, Tampilan & Akun, Koneksi) -- pola sama dgn
   .crm-group-title tapi dipakai di atas KARTU, bukan di dalam .crm-list. */
.settings-section-label {
  font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--app-text-muted); margin: 0 0 8px 2px;
}
.settings-section-label:not(:first-of-type) { margin-top: 4px; }

/* ---------------------------------------------------------------------
 * Transisi halaman (native Cross-Document View Transitions)
 * ------------------------------------------------------------------- *
 * Cara kerja: browser yang mendukung (Chrome/Edge 126+, Safari 18.2+)
 * otomatis mengambil "snapshot" halaman lama & halaman baru lalu
 * meng-animasikan bedanya SAAT navigasi <a href> normal terjadi -- tidak
 * butuh AJAX/JS router sama sekali, jadi semua polling/inline <script>
 * per-halaman (chat, session/connect, dsb) tetap jalan apa adanya persis
 * seperti sebelumnya (full page load asli, cuma dibungkus animasi).
 *
 * Browser yang belum dukung (Firefox saat ini) otomatis fallback ke
 * navigasi biasa tanpa animasi -- tidak ada yang rusak/error.
 *
 * Elemen yang diberi `view-transition-name` unik (topbar, sidebar,
 * bottom-nav) di-"morph" oleh browser antara dua halaman alih-alih ikut
 * di-cross-fade bareng konten -- inilah yang membuat bottom navbar
 * terlihat TETAP TAMPIL (tidak sempat hilang/kedip) selama loading
 * berpindah halaman, karena kedua dokumen sama-sama merender bottom-nav
 * yang identik di posisi yang sama. */
@view-transition {
  navigation: auto;
}

/* Konten utama (main.app-main / <main> tamu login) dibiarkan pakai
   animasi default root (cross-fade) TAPI diperhalus jadi fade + sedikit
   slide naik/turun, bukan potongan tegas -- inilah "efek lembut" saat
   berpindah halaman. */
::view-transition-old(root) {
  animation: crm-page-out .22s cubic-bezier(.4, 0, .2, 1) both;
}
::view-transition-new(root) {
  animation: crm-page-in .28s cubic-bezier(.16, 1, .3, 1) both;
}
@keyframes crm-page-out {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-6px); }
}
@keyframes crm-page-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Nav persisten: diberi nama transisi sendiri supaya browser meng-"morph"
   elemen ini instan (bukan fade out lalu fade in) antar halaman -- efeknya
   terlihat seolah tidak pernah hilang selama loading. */
.bottom-nav { view-transition-name: crm-bottom-nav; }
#topbar     { view-transition-name: crm-topbar; }
#sidebar    { view-transition-name: crm-sidebar; }

/* Elemen ber-nama tidak boleh dobel dalam satu waktu; sheet "Lainnya" &
   backdrop-nya sengaja TIDAK diberi nama (selalu tertutup saat pindah
   halaman) supaya tidak konflik/duplikat nama transisi. */

/* Hormati preferensi pengguna yang sensitif terhadap animasi/gerakan. */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* Progress bar tipis di paling atas layar (lihat page-transition.js) --
   nempel di viewport (bukan ikut nav manapun) supaya tetap kelihatan di
   atas topbar/sidebar/bottom-nav selama loading pindah halaman. */
#crmPageLoadBar {
  position: fixed; top: 0; left: 0; height: 3px; width: 0%;
  background: linear-gradient(90deg, var(--crm-brand), var(--crm-brand-hover, var(--crm-brand)));
  z-index: 9999; opacity: 0; pointer-events: none;
  border-radius: 0 2px 2px 0;
  box-shadow: 0 0 8px 0 rgb(var(--crm-brand-rgb) / .5);
}
#crmPageLoadBar.is-loading {
  opacity: 1;
  animation: crm-loadbar-progress 6s cubic-bezier(.1, .6, .3, 1) forwards;
}
@keyframes crm-loadbar-progress {
  0%   { width: 0%; }
  15%  { width: 35%; }
  40%  { width: 58%; }
  70%  { width: 78%; }
  100% { width: 92%; }
}
@media (prefers-reduced-motion: reduce) {
  #crmPageLoadBar { display: none; }
}

/* =====================================================================
 * REDESAIN HALAMAN CHAT -- gaya app Claude AI Android
 * -----------------------------------------------------------------------
 * Khusus /chat (body.claude-chat-page, di-set server-side di
 * layout/header.php). Halaman ini TIDAK lagi memakai sidebar/topbar/
 * bottom-nav global (lihat cabang $isChatPage di header.php/footer.php) --
 * satu layar penuh, sendiri. Daftar chat (.chat-list) bukan lagi kolom
 * tetap di samping seperti sebelumnya, tapi DRAWER yang menutupi layar
 * dari kiri (persis pola Claude Android: ikon hamburger di kiri-atas
 * panel percakapan membuka daftar riwayat chat sebagai overlay), berlaku
 * di SEMUA lebar layar -- bukan cuma mobile -- karena referensinya
 * memang app Android (selalu 1 kolom), bukan tampilan split desktop.
 * Semua rule di bawah discope ke body.claude-chat-page + .claude-shell
 * supaya tidak menyentuh halaman lain sama sekali, dan sengaja ditulis
 * TANPA media query supaya specificity-nya (lihat kombinasi class)
 * selalu menang atas rule lama `.chat-list`/`.chat-panel` di atas, di
 * lebar layar berapa pun -- tidak perlu duplikasi per breakpoint lagi. */

body.claude-chat-page {
  /* Poin update: palet chat sekarang IKUT WARNA SISTEM (token warna brand
     dan warna permukaan yang sama dipakai di seluruh app, termasuk warna
     brand custom dari halaman Pengaturan & tema terang/gelap) -- bukan lagi
     warna "clay" oranye-terakota Claude yang di-hardcode terpisah. Nama
     variabel --claude-* DIPERTAHANKAN (dipakai puluhan rule di bawah)
     supaya tidak perlu tulis ulang semuanya, tapi NILAINYA sekarang murni
     alias ke token sistem -- ganti warna brand di Pengaturan atau ganti
     tema otomatis ikut berubah di halaman chat juga, tanpa perlu blok
     override terpisah untuk dark mode lagi (token sistem yang dialiaskan
     di sini sudah berubah otomatis sendiri lewat data-bs-theme dark di
     root, jadi cukup alias sekali saja di sini). */
  --claude-accent:      var(--crm-brand);
  --claude-accent-hover:var(--crm-brand-hover);
  --claude-accent-text: var(--on-brand);
  --claude-bg:          var(--app-body-bg);
  --claude-drawer-bg:   var(--app-surface-alt);
  --claude-surface:     var(--app-surface);
  --claude-surface-alt: var(--app-surface-alt);
  --claude-border:      var(--app-border);
  --claude-text:        var(--app-text);
  --claude-text-muted:  var(--app-text-muted);
  --claude-text-faint:  var(--app-text-faint);
  --claude-bubble-in:   var(--app-surface);
  --claude-bubble-in-text: var(--app-text);
  --claude-shadow:      var(--shadow-md);
  background: var(--claude-bg);
  overscroll-behavior: none;
}

/* Flash pesan sukses/gagal (dipindah dari dalam <main> lama, karena
   halaman chat tidak lagi punya wadah itu) -- mengambang di atas semua. */
.claude-flash {
  position: fixed; top: calc(12px + env(safe-area-inset-top, 0px)); left: 50%;
  transform: translateX(-50%); z-index: 200; max-width: min(92vw, 420px);
  padding: var(--space-10px) var(--space-16px); border-radius: var(--radius-md);
  font-size: var(--text-sm); font-weight: 600; box-shadow: var(--claude-shadow);
}
.claude-flash-success { background: var(--crm-color-success-bg); color: var(--crm-color-success); }
.claude-flash-error   { background: var(--crm-color-danger-bg); color: var(--crm-color-danger-text); }

/* Shell penuh layar, tanpa kartu/border/radius seperti dulu. */
body.claude-chat-page .chat-shell.claude-shell {
  position: fixed; inset: 0;
  height: 100dvh; height: calc(var(--crm-vvh, 100dvh));
  width: 100vw; border: 0; border-radius: 0; box-shadow: none;
  background: var(--claude-bg); overflow: hidden;
}

/* Bottom-nav sekarang ikut dirender di halaman Chat (lihat header.php) --
   sisakan ruang di bawah shell supaya navbar tidak menutupi komposer/
   daftar chat. Cuma perlu media query DI SINI (bukan pelanggaran catatan
   "tanpa media query" di atas -- itu soal drawer/panel yang perilakunya
   sama di semua lebar; bottom-nav sendiri memang cuma tampil <1024px,
   ikut breakpoint .bottom-nav yang sudah ada di atas). var(--bottom-nav-height)
   otomatis jadi 0 lewat body.crm-chat-open saat satu chat lagi dibuka di
   mobile (Poin 11 di bawah), jadi shell otomatis full-height lagi saat itu. */
@media (max-width: 1023.98px) {
  body.claude-chat-page .chat-shell.claude-shell {
    bottom: var(--bottom-nav-height);
    height: calc(var(--crm-vvh, 100dvh) - var(--bottom-nav-height));
  }
}

/* -- Panel percakapan: SELALU tampil penuh lebar (daftar chat bukan lagi
   pane sebelah, jadi tidak perlu lagi disembunyikan gantian). -- */
body.claude-chat-page .chat-shell.claude-shell .chat-panel {
  display: flex; width: 100%; background: var(--claude-bg);
}

/* -- Drawer daftar chat -- */
body.claude-chat-page .chat-shell.claude-shell .chat-list {
  /* PENTING: display:flex di-set eksplisit di sini (bukan cuma diwarisi)
     supaya spesifisitasnya menang lawan aturan single-pane lama
     `.chat-shell.has-active .chat-list { display: none; }` (Poin 1 &
     js-force-single-pane di atas). Kalau tidak, saat sebuah chat sedang
     aktif elemen ini jadi display:none dan transform di bawah (yang
     mengatur buka/tutup drawer via hamburger) tidak akan pernah kelihatan
     efeknya -- persis bug "klik hamburger tidak ada reaksi". Visibilitas
     drawer SEHARUSNYA murni dikendalikan oleh transform, bukan display. */
  display: flex; flex-direction: column;
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 70;
  width: min(340px, 86vw); max-width: 340px;
  background: var(--claude-drawer-bg); border-right: 1px solid var(--claude-border);
  box-shadow: var(--claude-shadow);
  transform: translateX(-100%);
  transition: transform .26s cubic-bezier(.32,.72,0,1);
  padding-top: env(safe-area-inset-top, 0px);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
body.claude-chat-page .chat-shell.claude-shell.sidebar-open .chat-list {
  transform: translateX(0);
}
/* Poin 18: kombinasi "drawer terbuka" + "belum ada chat aktif" cuma
   kejadian saat halaman /chat baru dibuka (server-render awal, lihat
   chat/index.php) -- di kondisi INI SAJA daftar chat berperan sebagai
   layar utama/home (bukan overlay drawer sempit di atas thread aktif),
   jadi lebar dipaksa penuh & border/shadow drawer dilepas supaya benar-
   benar terasa seperti "halaman", bukan panel yang menempel. Begitu satu
   chat dipilih (has-active), aturan ini otomatis tidak berlaku lagi dan
   drawer balik ke ukuran overlay 340px standar seperti sebelumnya. */
body.claude-chat-page .chat-shell.claude-shell.sidebar-open:not(.has-active) .chat-list {
  width: 100%; max-width: 100%; border-right: 0; box-shadow: none;
}
.chat-list-backdrop {
  position: fixed; inset: 0; z-index: 65; background: rgba(20, 16, 12, .45);
  opacity: 0; pointer-events: none; transition: opacity .22s ease;
}
body.claude-chat-page .chat-shell.claude-shell.sidebar-open .chat-list-backdrop {
  opacity: 1; pointer-events: auto;
}
/* Drawer & backdrop-nya independen (fixed relatif ke viewport, bukan ke
   .chat-shell), jadi perlu disisakan ruang bottom-nav terpisah juga di
   sini -- kalau tidak, keduanya tetap menutupi navbar walau .chat-shell
   sendiri sudah berhenti di atasnya (lihat override serupa untuk
   .chat-shell sendiri di atas). HARUS diletakkan SETELAH rule dasar
   .chat-list/.chat-list-backdrop di atas (spesifisitas selector-nya sama
   persis, jadi urutan sumber yang menentukan siapa menang) -- otomatis
   kembali menutup penuh layar (var(--bottom-nav-height) jadi 0) lewat
   body.crm-chat-open saat satu chat sedang dibuka di mobile, pas dengan
   saat itu juga bottom-nav memang sudah disembunyikan (Poin 11), jadi
   tidak ada celah kosong yang tersisa. */
@media (max-width: 1023.98px) {
  body.claude-chat-page .chat-shell.claude-shell .chat-list,
  body.claude-chat-page .chat-list-backdrop {
    bottom: var(--bottom-nav-height);
  }
}

/* Toolbar drawer (cari + filter) -- flat, tanpa frosted glass. */
body.claude-chat-page .chat-list-toolbar {
  background: var(--claude-drawer-bg); border-bottom: 1px solid var(--claude-border);
  padding: calc(var(--space-12px) + env(safe-area-inset-top, 0px)) var(--space-12px) var(--space-10px);
}
body.claude-chat-page .chat-search {
  background: var(--claude-surface); border: 1px solid var(--claude-border); color: var(--claude-text-muted);
}
body.claude-chat-page .chat-search input { color: var(--claude-text); }
body.claude-chat-page .chat-search input::placeholder { color: var(--claude-text-faint); }
body.claude-chat-page .chat-filter-tabs { background: var(--claude-surface); border-color: var(--claude-border); }
body.claude-chat-page .btn-filter { color: var(--claude-text-muted); }
body.claude-chat-page .btn-filter:hover { color: var(--claude-text); }
body.claude-chat-page .btn-filter.active { background: var(--claude-accent); color: var(--claude-accent-text); box-shadow: none; }
body.claude-chat-page .btn-status-filter { border-color: var(--claude-border); color: var(--claude-text-muted); }
body.claude-chat-page .btn-status-filter.active { background: color-mix(in srgb, var(--status-color, var(--claude-accent)) 16%, var(--claude-surface)); }

/* Daftar percakapan -- kartu baris membulat + highlight lembut saat aktif,
   pola persis daftar riwayat chat di app Claude (bukan garis pembatas
   ala WhatsApp). */
body.claude-chat-page .chat-list-items { padding: var(--space-6px) var(--space-8px); }
body.claude-chat-page .chat-list-item {
  border-radius: var(--radius-lg); margin-bottom: 2px; color: var(--claude-text);
}
body.claude-chat-page .chat-list-item:hover,
body.claude-chat-page .chat-list-item:active { background-color: var(--claude-surface-alt); }
body.claude-chat-page .chat-list-item.active { background-color: color-mix(in srgb, var(--claude-accent) 14%, transparent); }
body.claude-chat-page .chat-list-item .chat-number { color: var(--claude-text); }
body.claude-chat-page .chat-list-item .chat-preview,
body.claude-chat-page .chat-list-time { color: var(--claude-text-muted); }
body.claude-chat-page .chat-list-item.has-unread .chat-number,
body.claude-chat-page .chat-list-item.has-unread .chat-preview { color: var(--claude-text); }
body.claude-chat-page .chat-list-item.has-unread .chat-list-time { color: var(--claude-accent); }
body.claude-chat-page .chat-unread-badge { background: var(--claude-accent); }
body.claude-chat-page .chat-avatar.avatar-c1,
body.claude-chat-page .chat-avatar:not([class*="avatar-c"]) { background: var(--claude-accent); }
body.claude-chat-page .chat-fab { background: var(--claude-accent); box-shadow: var(--claude-shadow); }
body.claude-chat-page .chat-fab:hover { background: var(--claude-accent-hover); }

/* -- Bar mini di panel chat (hamburger + identitas + tombol chat baru) --
   flat tanpa frosted-glass, senada dengan header app Claude yang tipis
   dan tenang. .chat-back-btn dipakai ulang di sini sebagai tombol ikon
   hamburger & "chat baru" (bukan cuma tombol "kembali" seperti dulu),
   jadi dipaksa selalu tampil (default lamanya display:none). */
body.claude-chat-page .chat-back-btn {
  display: inline-flex !important;
  background: transparent; border: none; color: var(--claude-text-muted);
  margin: 0;
}
body.claude-chat-page .chat-back-btn:hover { background: var(--claude-surface-alt); color: var(--claude-text); }
body.claude-chat-page .chat-panel-header,
body.claude-chat-page .chat-tag-row {
  background: var(--claude-bg);
  -webkit-backdrop-filter: none; backdrop-filter: none;
  border-bottom: 1px solid var(--claude-border);
  padding-top: calc(var(--space-8px) + env(safe-area-inset-top, 0px));
}
body.claude-chat-page .chat-panel-header-title { color: var(--claude-text); }
body.claude-chat-page .chat-header-swipe-hint { color: var(--claude-text-faint); }
body.claude-chat-page .chat-panel-avatar { background: var(--claude-accent); }
body.claude-chat-page .chat-poll-dot { background: var(--claude-text-faint); }
body.claude-chat-page .chat-poll-dot.is-active { background: var(--claude-accent); }
body.claude-chat-page .claude-new-chat-btn { margin-left: 2px; }

/* Bar tipis yang sama saat BELUM ada percakapan dibuka -- supaya drawer
   tetap terjangkau lewat hamburger walau belum pilih chat mana pun. */
.claude-empty-topbar {
  display: flex; align-items: center; gap: 8px;
  padding: calc(var(--space-8px) + env(safe-area-inset-top, 0px)) var(--space-12px) var(--space-8px);
  border-bottom: 1px solid var(--claude-border); background: var(--claude-bg);
}
.claude-empty-topbar-title { flex: 1; min-width: 0; font-size: var(--text-sm); font-weight: 600; color: var(--claude-text); text-align: left; }

/* -- Timeline pesan -- */
body.claude-chat-page .chat-box-wrap,
body.claude-chat-page #chat-box { background: var(--claude-bg); }
body.claude-chat-page .chat-date-separator span {
  background: var(--claude-surface-alt); color: var(--claude-text-muted); border-color: var(--claude-border); box-shadow: none;
}
body.claude-chat-page .chat-bubble {
  border-radius: var(--radius-xl); box-shadow: none;
}
body.claude-chat-page .chat-bubble.in {
  background-color: var(--claude-bubble-in); border: 1px solid var(--claude-border);
  color: var(--claude-bubble-in-text); border-bottom-left-radius: var(--radius-sm);
}
body.claude-chat-page .chat-bubble.out {
  background-color: var(--claude-accent); color: var(--claude-accent-text);
  border-bottom-right-radius: var(--radius-sm);
}
body.claude-chat-page .chat-sticky-note { border-radius: var(--radius-lg); }
body.claude-chat-page .chat-scroll-bottom-btn {
  background: var(--claude-surface); border-color: var(--claude-border); color: var(--claude-text);
  -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: var(--claude-shadow);
}
body.claude-chat-page .chat-scroll-bottom-badge { background: var(--claude-accent); }
body.claude-chat-page .chat-empty { background-color: var(--claude-bg); color: var(--claude-text-muted); }
body.claude-chat-page .chat-empty .icon { color: var(--claude-text-faint); }

/* -- Composer: kapsul mengambang, bukan bar penuh lebar bergaris atas --
   pola input box Claude (rounded-full, shadow lembut, tanpa border tebal). */
/* Catatan: <form id="form-send-chat" class="chat-composer ..."> adalah SATU
   elemen yang sama (bukan wrapper + form terpisah) -- jadi pill-nya
   langsung diterapkan ke .chat-composer itu sendiri lewat margin (jarak ke
   tepi layar = kesan "mengambang") + border/radius/shadow, bukan dua layer. */
body.claude-chat-page .chat-composer {
  background: var(--claude-surface); border: 1px solid var(--claude-border);
  border-radius: 26px; box-shadow: var(--claude-shadow);
  margin: 0 var(--space-12px) calc(var(--space-10px) + env(safe-area-inset-bottom, 0px));
  padding: 6px 6px 6px 14px;
}
body.claude-chat-page .chat-textarea {
  background: transparent; border: none !important; box-shadow: none; color: var(--claude-text);
}
body.claude-chat-page .chat-textarea::placeholder { color: var(--claude-text-faint); }
body.claude-chat-page .chat-note-toggle-btn { color: var(--claude-text-muted); }
body.claude-chat-page #chatSendBtn { background: var(--claude-accent); color: var(--claude-accent-text); }
body.claude-chat-page #chatSendBtn:hover { background: var(--claude-accent-hover); }
body.claude-chat-page .chat-note-composer {
  background: var(--claude-surface-alt); border: 1px solid var(--claude-border); border-radius: var(--radius-lg);
  margin: 0 var(--space-12px) var(--space-8px);
}

/* Kunci scroll body saat drawer terbuka -- reuse class crm-scroll-locked
   yang sudah ada (dipakai bottom sheet lain), cukup dipastikan aktif juga
   di halaman chat (rule aslinya global, jadi otomatis berlaku di sini). */

/* -- Sentuhan akhir: bottom sheet (pilih grup / info percakapan), pill
   status pipeline, & chip tag di halaman chat ikut memakai aksen "clay"
   Claude, bukan lagi hijau brand default -- supaya satu halaman ini
   terasa konsisten sebagai satu produk, bukan campuran dua palet. */
body.claude-chat-page .crm-more-sheet { background: var(--claude-surface); }
body.claude-chat-page .crm-more-header { border-color: var(--claude-border); }
body.claude-chat-page .crm-more-title { color: var(--claude-text); }
body.claude-chat-page .crm-row-title { color: var(--claude-text); }
body.claude-chat-page .crm-row-subtitle { color: var(--claude-text-muted); }
body.claude-chat-page .crm-row.is-accent { color: var(--claude-accent); }
body.claude-chat-page .group-sheet-item:hover,
body.claude-chat-page .group-sheet-item:active,
body.claude-chat-page a.crm-row:active,
body.claude-chat-page button.crm-row:active { background: var(--claude-surface-alt); }
body.claude-chat-page .chat-pipeline-pill,
body.claude-chat-page .chat-tag-add-btn {
  border-color: var(--claude-border); color: var(--claude-text-muted); background: var(--claude-surface);
}
/* BUG FIX: komentar di atas ("chip tag ikut memakai aksen clay Claude")
   sudah lama menjanjikan ini, tapi rule-nya sendiri belum pernah ditulis --
   akibatnya chip "Premium"/"Grup Arabiyah" dkk masih pakai warna tag penuh
   (bg+border+teks ikut --tag-color, lihat .tag-chip base), jadi kelihatan
   beda gaya dari pill Follow-up (.chat-pipeline-pill) yang sudah netral.
   Disamakan persis: border/bg/teks netral, warna tag TETAP kelihatan lewat
   titik (::before, tidak disentuh di sini) -- sama seperti pill Follow-up
   yang cuma nyalain warna di .status-dot, bukan di seluruh pill. */
body.claude-chat-page .chat-tag-chip {
  border-color: var(--claude-border); color: var(--claude-text-muted); background: var(--claude-surface);
}
body.claude-chat-page .chat-tag-chip-remove {
  background: var(--claude-surface-alt); color: var(--claude-text-muted);
}
body.claude-chat-page .chat-tag-chip-remove:hover { background: var(--claude-border); color: var(--claude-text); }
body.claude-chat-page .chat-tag-empty,
body.claude-chat-page .chat-tag-add-disabled { color: var(--claude-text-faint); }
body.claude-chat-page .btn-pipeline-option.is-active { color: var(--status-color, var(--claude-accent)); }
body.claude-chat-page .inline-flex.bg-brand { background: var(--claude-accent) !important; }
body.claude-chat-page .inline-flex.bg-brand:hover { background: var(--claude-accent-hover) !important; }
