/* ==========================================================================
   MyAsistant — operations console stylesheet
   1. Tokens   2. Reset   3. Layout   4. Components   5. Pages   6. Responsive
   ========================================================================== */

/* 1. TOKENS ================================================================ */

:root {
  /* neutral ramp (slate) */
  --n-50:#f8fafc;  --n-100:#f1f5f9; --n-200:#e2e8f0; --n-300:#cbd5e1;
  --n-400:#94a3b8; --n-500:#64748b; --n-600:#475569; --n-700:#334155;
  --n-800:#1e293b; --n-900:#0f172a; --n-950:#020617;

  /* accent — emerald/teal */
  --a-50:#ecfdf5;  --a-100:#d1fae5; --a-200:#a7f3d0; --a-300:#6ee7b7;
  --a-400:#34d399; --a-500:#10b981; --a-600:#059669; --a-700:#047857;
  --a-800:#065f46; --a-900:#064e3b;

  /* secondary — violet (AI) */
  --v-50:#f5f3ff;  --v-100:#ede9fe; --v-200:#ddd6fe; --v-300:#c4b5fd;
  --v-400:#a78bfa; --v-500:#8b5cf6; --v-600:#7c3aed; --v-700:#6d28d9;

  /* semantic hues */
  --h-success:#059669; --h-warning:#d97706; --h-danger:#dc2626; --h-info:#0284c7;

  /* surfaces (light) */
  --bg:           #f4f6f9;
  --bg-grid:      rgba(15,23,42,.035);
  --surface:      #ffffff;
  --surface-2:    #f8fafc;
  --surface-3:    #f1f5f9;
  --surface-sunk: #eef2f7;
  --overlay:      rgba(15,23,42,.45);

  --border:        #e3e8ef;
  --border-strong: #cfd6e0;
  --border-soft:   #eef1f5;

  --text:   #0f172a;
  --text-2: #475569;
  --text-3: #7a8699;
  --text-inv:#ffffff;

  --accent:      var(--a-600);
  --accent-hover:var(--a-700);
  --accent-text: var(--a-700);
  --accent-fg:   #ffffff;
  --accent-soft: var(--a-50);
  --accent-ring: rgba(5,150,105,.32);

  --violet:      var(--v-600);
  --violet-text: var(--v-700);
  --violet-soft: var(--v-50);
  --violet-line: var(--v-200);

  --success:var(--h-success); --success-soft:#ecfdf5;
  --warning:var(--h-warning); --warning-soft:#fffbeb;
  --danger: var(--h-danger);  --danger-soft:#fef2f2;
  --info:   var(--h-info);    --info-soft:#f0f9ff;

  --shadow-1: 0 1px 2px rgba(15,23,42,.05), 0 1px 3px rgba(15,23,42,.06);
  --shadow-2: 0 10px 15px -3px rgba(15,23,42,.08), 0 4px 6px -4px rgba(15,23,42,.06);
  --shadow-3: 0 24px 48px -12px rgba(15,23,42,.22);

  /* bubbles */
  --bubble-in:#ffffff; --bubble-in-br:var(--border);
  --bubble-out:var(--a-50); --bubble-out-br:#bdebd8;
  --bubble-ai:var(--v-50); --bubble-ai-br:var(--v-200);

  /* chart */
  --chart-in:  var(--a-500);
  --chart-out: var(--v-500);
  --chart-grid: var(--border);
  --chart-axis: var(--text-3);
  /* Categorical palette (validated, fixed order — dataviz skill). Light steps. */
  --cat-1:#2a78d6; --cat-2:#eb6834; --cat-3:#1baf7a; --cat-4:#eda100;
  --cat-5:#e87ba4; --cat-6:#008300; --cat-7:#4a3aa7; --cat-8:#e34948;

  /* geometry */
  --r-xs:6px; --r-sm:8px; --r-md:10px; --r-lg:12px; --r-xl:14px; --r-2xl:18px; --r-pill:999px;
  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px; --s-5:24px; --s-6:32px; --s-7:48px; --s-8:64px;
  --sidebar-w:248px;
  --topbar-h:60px;
  --fast:120ms; --base:150ms; --slow:240ms;
  --ease: cubic-bezier(.4,0,.2,1);

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, "Helvetica Neue",
          "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
  --mono: ui-monospace, SFMono-Regular, "SF Mono", "JetBrains Mono", Menlo, Consolas,
          "Liberation Mono", monospace;
}

:root[data-theme="dark"] {
  --bg:           #080b11;
  --bg-grid:      rgba(255,255,255,.028);
  --surface:      #11161f;
  --surface-2:    #161d28;
  --surface-3:    #1c2431;
  --surface-sunk: #0c1016;
  --overlay:      rgba(2,6,23,.72);

  --border:        #222b39;
  --border-strong: #313d4f;
  --border-soft:   #1a222e;

  --text:   #e8edf5;
  --text-2: #a5b0c0;
  --text-3: #73808f;
  --text-inv:#06110c;

  --accent:      var(--a-500);
  --accent-hover:var(--a-400);
  --accent-text: var(--a-300);
  --accent-fg:   #04140d;
  --accent-soft: rgba(16,185,129,.12);
  --accent-ring: rgba(52,211,153,.4);

  --violet:      var(--v-500);
  --violet-text: var(--v-300);
  --violet-soft: rgba(139,92,246,.14);
  --violet-line: rgba(139,92,246,.32);

  --success:#34d399; --success-soft:rgba(16,185,129,.13);
  --warning:#fbbf24; --warning-soft:rgba(245,158,11,.14);
  --danger: #f87171; --danger-soft:rgba(239,68,68,.14);
  --info:   #38bdf8; --info-soft:rgba(14,165,233,.14);

  --shadow-1: 0 1px 2px rgba(0,0,0,.5);
  --shadow-2: 0 12px 24px -10px rgba(0,0,0,.7), 0 2px 6px rgba(0,0,0,.4);
  --shadow-3: 0 28px 60px -16px rgba(0,0,0,.8);

  --bubble-in:#19212c; --bubble-in-br:#273242;
  --bubble-out:rgba(16,185,129,.14); --bubble-out-br:rgba(52,211,153,.32);
  --bubble-ai:rgba(139,92,246,.15); --bubble-ai-br:rgba(167,139,250,.35);

  --chart-in:  var(--a-400);
  --chart-out: var(--v-400);
  --chart-grid: #222b39;
  --chart-axis: var(--text-3);
  --cat-1:#3987e5; --cat-2:#d95926; --cat-3:#199e70; --cat-4:#c98500;
  --cat-5:#d55181; --cat-6:#008300; --cat-7:#9085e9; --cat-8:#e66767;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:#080b11; --bg-grid:rgba(255,255,255,.028);
    --surface:#11161f; --surface-2:#161d28; --surface-3:#1c2431; --surface-sunk:#0c1016;
    --overlay:rgba(2,6,23,.72);
    --border:#222b39; --border-strong:#313d4f; --border-soft:#1a222e;
    --text:#e8edf5; --text-2:#a5b0c0; --text-3:#73808f; --text-inv:#06110c;
    --accent:var(--a-500); --accent-hover:var(--a-400); --accent-text:var(--a-300);
    --accent-fg:#04140d; --accent-soft:rgba(16,185,129,.12); --accent-ring:rgba(52,211,153,.4);
    --violet:var(--v-500); --violet-text:var(--v-300);
    --violet-soft:rgba(139,92,246,.14); --violet-line:rgba(139,92,246,.32);
    --success:#34d399; --success-soft:rgba(16,185,129,.13);
    --warning:#fbbf24; --warning-soft:rgba(245,158,11,.14);
    --danger:#f87171;  --danger-soft:rgba(239,68,68,.14);
    --info:#38bdf8;    --info-soft:rgba(14,165,233,.14);
    --shadow-1:0 1px 2px rgba(0,0,0,.5);
    --shadow-2:0 12px 24px -10px rgba(0,0,0,.7), 0 2px 6px rgba(0,0,0,.4);
    --shadow-3:0 28px 60px -16px rgba(0,0,0,.8);
    --bubble-in:#19212c; --bubble-in-br:#273242;
    --bubble-out:rgba(16,185,129,.14); --bubble-out-br:rgba(52,211,153,.32);
    --bubble-ai:rgba(139,92,246,.15); --bubble-ai-br:rgba(167,139,250,.35);
    --chart-in:var(--a-400); --chart-out:var(--v-400);
    --chart-grid:#222b39; --chart-axis:var(--text-3);
    --cat-1:#3987e5; --cat-2:#d95926; --cat-3:#199e70; --cat-4:#c98500;
    --cat-5:#d55181; --cat-6:#008300; --cat-7:#9085e9; --cat-8:#e66767;
  }
}

/* 2. RESET ================================================================= */

/* The scripts hide and show panels with the `hidden` attribute. Any author rule
   that sets `display` on the same element would otherwise win over the browser
   default for [hidden] and leave the element stuck on screen, so make the
   attribute authoritative. */
[hidden] { display:none !important; }

*,*::before,*::after { box-sizing:border-box; }
* { margin:0; }
html { -webkit-text-size-adjust:100%; }
body {
  font-family:var(--font);
  font-size:13.5px;
  line-height:1.55;
  color:var(--text);
  background:var(--bg);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  min-height:100dvh;
}
h1,h2,h3,h4 { line-height:1.25; font-weight:650; letter-spacing:-.011em; }
h1 { font-size:1.125rem; }
h2 { font-size:1rem; }
h3 { font-size:.9375rem; }
h4 { font-size:.875rem; }
p { text-wrap:pretty; }
a { color:var(--accent-text); text-decoration:none; }
a:hover { text-decoration:underline; }
img,svg { display:block; max-width:100%; }
button,input,select,textarea { font:inherit; color:inherit; }
button { background:none; border:0; cursor:pointer; }
table { border-collapse:collapse; width:100%; }
ul,ol { list-style:none; padding:0; }
code,kbd,pre,.mono,.num { font-family:var(--mono); }
.num,table td,.stat-value { font-variant-numeric:tabular-nums; }
hr { border:0; border-top:1px solid var(--border); margin:var(--s-4) 0; }

:focus-visible {
  outline:2px solid var(--accent);
  outline-offset:2px;
  border-radius:var(--r-xs);
}
::selection { background:var(--accent-soft); color:var(--accent-text); }

::-webkit-scrollbar { width:10px; height:10px; }
::-webkit-scrollbar-track { background:transparent; }
::-webkit-scrollbar-thumb { background:var(--border-strong); border-radius:99px; border:3px solid transparent; background-clip:content-box; }
::-webkit-scrollbar-thumb:hover { background:var(--text-3); background-clip:content-box; border:3px solid transparent; }

.sr-only {
  position:absolute; width:1px; height:1px; padding:0; overflow:hidden;
  clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap; border:0;
}
.skip-link {
  position:fixed; left:var(--s-3); top:-60px; z-index:200;
  background:var(--surface); color:var(--text); padding:var(--s-2) var(--s-4);
  border:1px solid var(--border); border-radius:var(--r-sm); box-shadow:var(--shadow-2);
  transition:top var(--base) var(--ease);
}
.skip-link:focus { top:var(--s-3); }

.muted { color:var(--text-2); }
.dim { color:var(--text-3); }
.tiny { font-size:.6875rem; }
.small { font-size:.75rem; }
.strong { font-weight:650; }
.truncate { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
.clamp-2 { display:-webkit-box; -webkit-line-clamp:2; line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.clamp-3 { display:-webkit-box; -webkit-line-clamp:3; line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; }
.row { display:flex; align-items:center; gap:var(--s-2); }
.row-between { display:flex; align-items:center; justify-content:space-between; gap:var(--s-3); }
.wrap { flex-wrap:wrap; }
.grow { flex:1; min-width:0; }
.stack { display:flex; flex-direction:column; gap:var(--s-3); }
.stack-sm { display:flex; flex-direction:column; gap:var(--s-2); }
.ico { width:18px; height:18px; flex:none; }
.ico-sm { width:15px; height:15px; }
.ico-lg { width:22px; height:22px; }

/* 3. LAYOUT ================================================================ */

.sidebar {
  position:fixed; inset:0 auto 0 0; width:var(--sidebar-w); z-index:60;
  display:flex; flex-direction:column;
  background:var(--surface); border-right:1px solid var(--border);
}
.sidebar-brand {
  display:flex; align-items:center; justify-content:space-between; gap:var(--s-2);
  height:var(--topbar-h); padding:0 var(--s-4);
  border-bottom:1px solid var(--border-soft); flex:none;
}
.brand { display:flex; align-items:center; gap:10px; color:var(--text); min-width:0; }
.brand:hover { text-decoration:none; }
.brand-mark { width:30px; height:30px; flex:none; border-radius:9px; }
.brand-text { display:flex; flex-direction:column; min-width:0; }
.brand-text strong { font-size:.9375rem; letter-spacing:-.02em; }
.brand-text small { font-size:.625rem; color:var(--text-3); text-transform:uppercase; letter-spacing:.09em; }
.sidebar-toggle { flex:none; }

.nav { flex:1; overflow-y:auto; padding:var(--s-4) var(--s-3) var(--s-2); }
.nav-group + .nav-group { margin-top:var(--s-5); }
.nav-label {
  font-size:.625rem; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  color:var(--text-3); padding:0 var(--s-3) var(--s-2);
}
.nav-list { display:flex; flex-direction:column; gap:2px; }
.nav-list[hidden] { display:none; }
/* collapsible groups: the label is a button; only "Utama" stays a plain label */
.nav-toggle {
  display:flex; align-items:center; justify-content:space-between; width:100%;
  border:0; background:transparent; cursor:pointer; text-align:left; border-radius:var(--r-sm);
}
.nav-toggle:hover { color:var(--text-2); }
.nav-toggle:focus-visible { outline:none; box-shadow:0 0 0 3px var(--accent-ring); }
.nav-toggle .ico { width:14px; height:14px; transition:transform var(--base) var(--ease); }
.nav-toggle[aria-expanded="true"] .ico { transform:rotate(180deg); }
.nav-item {
  position:relative; display:flex; align-items:center; gap:10px;
  padding:8px var(--s-3); border-radius:var(--r-md);
  color:var(--text-2); font-weight:500; font-size:.8125rem;
  transition:background var(--base) var(--ease), color var(--base) var(--ease);
}
.nav-item:hover { background:var(--surface-3); color:var(--text); text-decoration:none; }
.nav-item .ico { color:var(--text-3); transition:color var(--base) var(--ease); }
.nav-item:hover .ico { color:var(--text-2); }
.nav-item.is-active { background:var(--accent-soft); color:var(--accent-text); font-weight:600; }
.nav-item.is-active .ico { color:var(--accent); }
.nav-item.is-active::before {
  content:""; position:absolute; left:-12px; top:50%; transform:translateY(-50%);
  width:3px; height:18px; border-radius:0 3px 3px 0; background:var(--accent);
}
.nav-badge {
  margin-left:auto; font-style:normal; font-size:.6875rem; font-weight:700;
  background:var(--danger); color:#fff; border-radius:var(--r-pill);
  min-width:19px; height:19px; display:grid; place-items:center; padding:0 5px;
}

.sidebar-foot {
  flex:none; padding:var(--s-3) var(--s-4); border-top:1px solid var(--border-soft);
  display:flex; flex-direction:column; gap:6px;
}
.sidebar-foot .ws-state { display:none; }
.sidebar-foot .nav-item-foot { margin:0 calc(-1 * var(--s-2)) 2px; }

/* Documentation page: sticky table of contents beside long prose. */
.docs { display:grid; grid-template-columns:240px minmax(0,1fr); gap:var(--s-4); align-items:start; }
.docs-toc { position:sticky; top:calc(var(--topbar-h, 56px) + var(--s-4)); }
.docs-toc ol { list-style:none; display:flex; flex-direction:column; gap:2px; counter-reset:toc; }
.docs-toc li a { display:block; padding:6px 8px; border-radius:8px; font-size:.8125rem; color:var(--text-2); }
.docs-toc li a:hover { background:var(--surface-2); color:var(--text); }
.docs-body { display:flex; flex-direction:column; gap:var(--s-4); max-width:none; }
.docs-body section { scroll-margin-top:calc(var(--topbar-h, 56px) + var(--s-4)); }
.docs-body section h3 { font-size:1rem; margin-bottom:var(--s-3); }
.docs-body p, .docs-body ul { max-width:76ch; }
.docs-body kbd { font:inherit; font-size:.75rem; padding:1px 6px; border:1px solid var(--border); border-bottom-width:2px; border-radius:5px; background:var(--surface-2); }
@media (max-width: 900px) {
  .docs { grid-template-columns:1fr; }
  .docs-toc { position:static; }
}

.shell { margin-left:var(--sidebar-w); display:flex; flex-direction:column; min-height:100dvh; }

.topbar {
  position:sticky; top:0; z-index:50; flex:none;
  height:var(--topbar-h); display:flex; align-items:center; gap:var(--s-3);
  padding:0 var(--s-5);
  background:color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter:saturate(1.4) blur(12px);
  border-bottom:1px solid var(--border);
}
.topbar-title { flex:none; font-size:.9375rem; font-weight:650; letter-spacing:-.01em; }
.topbar-search { position:relative; flex:1; max-width:440px; margin-left:var(--s-3); }
.topbar-search > .ico {
  position:absolute; left:10px; top:50%; transform:translateY(-50%);
  color:var(--text-3); pointer-events:none;
}
.topbar-search input {
  width:100%; height:34px; padding:0 34px 0 34px;
  background:var(--surface-3); border:1px solid transparent; border-radius:var(--r-md);
  color:var(--text); font-size:.8125rem;
  transition:background var(--base) var(--ease), border-color var(--base) var(--ease);
}
.topbar-search input::placeholder { color:var(--text-3); }
.topbar-search input:focus { background:var(--surface); border-color:var(--border-strong); outline:none; box-shadow:0 0 0 3px var(--accent-ring); }
.topbar-search kbd {
  position:absolute; right:9px; top:50%; transform:translateY(-50%);
  font-size:.625rem; color:var(--text-3); background:var(--surface);
  border:1px solid var(--border); border-radius:5px; padding:1px 5px; line-height:1.4;
}
.topbar-search input:focus ~ kbd { opacity:0; }
.topbar-actions { margin-left:auto; display:flex; align-items:center; gap:var(--s-2); }

.search-results {
  position:absolute; top:calc(100% + 6px); left:0; right:0; z-index:70;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  box-shadow:var(--shadow-3); max-height:60vh; overflow-y:auto; padding:6px;
}
.search-group-label {
  font-size:.625rem; font-weight:700; letter-spacing:.09em; text-transform:uppercase;
  color:var(--text-3); padding:8px 10px 4px;
}
.search-hit { display:block; width:100%; text-align:left; padding:8px 10px; border-radius:var(--r-sm); color:var(--text); }
.search-hit:hover,.search-hit:focus-visible { background:var(--surface-3); text-decoration:none; }
.search-hit small { display:block; color:var(--text-3); font-size:.75rem; }

.main { flex:1; padding:var(--s-5); max-width:1560px; width:100%; }
/* The inbox owns the viewport: the thread scrolls inside itself and the
   composer stays pinned. `min-height:0` is what makes that work. A flex
   item defaults to min-height:auto, so .main would refuse to shrink below
   its content and grow the whole document instead, pushing the composer
   far below the fold. A fixed calc() height cannot fix that, because flex
   sizing wins over the height property on the main axis. */
body[data-page="inbox"] { overflow:hidden; }
body[data-page="inbox"] .shell { height:100dvh; min-height:0; }
body[data-page="inbox"] .main { flex:1 1 auto; min-height:0; height:auto;
  padding:0; max-width:none; overflow:hidden; }

.scrim {
  position:fixed; inset:0; z-index:55; background:var(--overlay);
  opacity:0; pointer-events:none; transition:opacity var(--base) var(--ease);
}
body.sidebar-open .scrim { opacity:1; pointer-events:auto; }

.page-head { display:flex; align-items:flex-start; justify-content:space-between; gap:var(--s-4); flex-wrap:wrap; margin-bottom:var(--s-5); }
.page-head h2 { font-size:1.0625rem; }
.page-head p { color:var(--text-2); font-size:.8125rem; margin-top:2px; }
.page-head-actions { display:flex; align-items:center; gap:var(--s-2); flex-wrap:wrap; }

/* 4. COMPONENTS ============================================================ */

/* --- card --- */
.card {
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-xl); box-shadow:var(--shadow-1);
}
.card-head {
  display:flex; align-items:center; justify-content:space-between; gap:var(--s-3);
  padding:var(--s-4) var(--s-4); border-bottom:1px solid var(--border-soft);
}
.card-head h3 { font-size:.875rem; }
.card-head p { font-size:.75rem; color:var(--text-3); }
.card-body { padding:var(--s-4); }
.card-body.flush { padding:0; }
.card-foot { padding:var(--s-3) var(--s-4); border-top:1px solid var(--border-soft); background:var(--surface-2); border-radius:0 0 var(--r-xl) var(--r-xl); }

.grid { display:grid; gap:var(--s-4); }
.grid-stats { grid-template-columns:repeat(auto-fit,minmax(176px,1fr)); }
/* The dashboard's six tiles are one row, as asked: they are the first thing
   on the page and reading them should take one glance, not two.
   
   It is scoped to [data-stats] rather than applied to .grid-stats, because the
   other pages that use that class have nine or more tiles and one row of nine
   is unreadable. minmax(0,1fr) rather than auto: without the 0 floor a long
   number sets the column's min-content width and the last tiles overflow the
   row instead of sharing it. The narrow breakpoints below still wrap — one row
   on a phone would be six illegible slivers. */
@media (min-width:1100px) {
  .grid.grid-stats[data-stats] { grid-template-columns:repeat(6,minmax(0,1fr)); }
  .grid.grid-stats[data-stats] .stat { padding:var(--s-3); min-width:0; }
  .grid.grid-stats[data-stats] .stat-value { font-size:1.5rem; }
  .grid.grid-stats[data-stats] .stat-label,
  .grid.grid-stats[data-stats] .stat-sub { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
}
@media (min-width:768px) and (max-width:1099px) {
  .grid.grid-stats[data-stats] { grid-template-columns:repeat(3,minmax(0,1fr)); }
}
.grid-2 { grid-template-columns:repeat(auto-fit,minmax(320px,1fr)); }
.grid-3 { grid-template-columns:repeat(auto-fill,minmax(300px,1fr)); }
.grid-dash { grid-template-columns:minmax(0,2fr) minmax(280px,1fr); align-items:start; }

/* --- stat tile --- */
.stat {
  position:relative; overflow:hidden;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-xl);
  padding:var(--s-4); box-shadow:var(--shadow-1);
  transition:border-color var(--base) var(--ease), transform var(--base) var(--ease);
}
.stat:hover { border-color:var(--border-strong); }
.stat-value-sm { font-size:1.125rem; line-height:1.3; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.stat-top { display:flex; align-items:center; justify-content:space-between; gap:var(--s-2); }
.stat-label { font-size:.6875rem; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--text-3); }
.stat-ico { width:30px; height:30px; display:grid; place-items:center; border-radius:9px; background:var(--surface-3); color:var(--text-2); }
.stat-ico .ico { width:16px; height:16px; }
.stat.is-accent .stat-ico { background:var(--accent-soft); color:var(--accent); }
.stat.is-violet .stat-ico { background:var(--violet-soft); color:var(--violet); }
.stat.is-info .stat-ico { background:var(--info-soft); color:var(--info); }
.stat.is-warning .stat-ico { background:var(--warning-soft); color:var(--warning); }
.stat.is-success .stat-ico { background:var(--success-soft); color:var(--success); }
.stat-value { font-size:1.75rem; font-weight:680; letter-spacing:-.03em; margin-top:10px; line-height:1.1; }
.stat-sub { font-size:.75rem; color:var(--text-3); margin-top:2px; }

/* --- buttons --- */
.btn {
  display:inline-flex; align-items:center; justify-content:center; gap:7px;
  height:34px; padding:0 13px; border-radius:var(--r-md);
  font-size:.8125rem; font-weight:560; white-space:nowrap;
  border:1px solid var(--border); background:var(--surface); color:var(--text);
  box-shadow:var(--shadow-1);
  transition:background var(--base) var(--ease), border-color var(--base) var(--ease),
             color var(--base) var(--ease), transform var(--fast) var(--ease);
}
.btn:hover { background:var(--surface-3); text-decoration:none; }
.btn:active { transform:translateY(1px); }
.btn .ico { width:16px; height:16px; }
.btn[disabled],.btn.is-busy { opacity:.55; pointer-events:none; }
.btn-primary { background:var(--accent); border-color:transparent; color:var(--accent-fg); }
.btn-primary:hover { background:var(--accent-hover); }
.btn-violet { background:var(--violet); border-color:transparent; color:#fff; }
.btn-violet:hover { filter:brightness(1.08); }
.btn-ghost { background:transparent; border-color:transparent; box-shadow:none; color:var(--text-2); }
.btn-ghost:hover { background:var(--surface-3); color:var(--text); }
.btn-outline { background:transparent; }
.btn-danger { background:var(--danger); border-color:transparent; color:#fff; }
:root[data-theme="dark"] .btn-danger { color:#1b0707; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .btn-danger { color:#1b0707; } }
:root[data-theme="light"] .btn-danger { color:#fff; }
.btn-danger:hover { filter:brightness(1.07); }
/* "Selesaikan" closes a conversation out. It is the one affirmative action in
   the chat header, so it gets the success colour rather than the accent that
   every other primary button in the app already uses — an operator should not
   have to read the label to find it. */
.btn-success { background:var(--success); border-color:transparent; color:#06281c; }
:root[data-theme="dark"] .btn-success { color:#06281c; }
.btn-success:hover { filter:brightness(1.07); }
.btn-danger-ghost { background:transparent; border-color:transparent; box-shadow:none; color:var(--danger); }
.btn-danger-ghost:hover { background:var(--danger-soft); }
.btn-sm { height:28px; padding:0 10px; font-size:.75rem; border-radius:var(--r-sm); }
.btn-sm .ico { width:14px; height:14px; }
.btn-lg { height:40px; padding:0 18px; font-size:.875rem; }
.btn-block { width:100%; }
.btn-icon {
  display:inline-grid; place-items:center; width:34px; height:34px; flex:none;
  border-radius:var(--r-md); color:var(--text-2); background:transparent;
  transition:background var(--base) var(--ease), color var(--base) var(--ease);
}
.btn-icon:hover { background:var(--surface-3); color:var(--text); }
.btn-icon.is-on { background:var(--accent-soft); color:var(--accent); }
.btn-icon-sm { width:28px; height:28px; border-radius:var(--r-sm); }
.btn-icon-sm .ico { width:15px; height:15px; }
.btn-icon.is-danger:hover { background:var(--danger-soft); color:var(--danger); }
.btn-group { display:inline-flex; gap:6px; flex-wrap:wrap; }

.spinner {
  width:14px; height:14px; flex:none; border-radius:50%;
  border:2px solid currentColor; border-right-color:transparent;
  animation:spin .7s linear infinite;
}
@keyframes spin { to { transform:rotate(360deg); } }

/* --- forms --- */
.field { display:flex; flex-direction:column; gap:5px; min-width:0; }
.field > label,.label {
  font-size:.75rem; font-weight:600; color:var(--text-2);
}
.field-hint { font-size:.6875rem; color:var(--text-3); }
/* A URL has no spaces to break at, so a resolved Cacti graph address either
   overflows its card or forces the whole modal wider. Breaking anywhere is the
   only option that keeps the layout put at phone width. */
.wrap-any { overflow-wrap:anywhere; min-width:0; }
.field-error { font-size:.6875rem; color:var(--danger); font-weight:500; }
.input,.select,.textarea {
  width:100%; min-height:34px; padding:7px 10px;
  background:var(--surface); color:var(--text);
  border:1px solid var(--border-strong); border-radius:var(--r-md);
  font-size:.8125rem;
  transition:border-color var(--base) var(--ease), box-shadow var(--base) var(--ease);
}
.input::placeholder,.textarea::placeholder { color:var(--text-3); }
.input:hover,.select:hover,.textarea:hover { border-color:var(--text-3); }
.input:focus,.select:focus,.textarea:focus {
  outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-ring);
}
.input[aria-invalid="true"],.textarea[aria-invalid="true"] { border-color:var(--danger); }
.input[disabled],.select[disabled],.textarea[disabled] { background:var(--surface-3); color:var(--text-3); cursor:not-allowed; }
.textarea { resize:vertical; min-height:84px; line-height:1.55; }
.select {
  appearance:none; padding-right:30px; cursor:pointer;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m6 9 6 6 6-6'/></svg>");
  background-repeat:no-repeat; background-position:right 9px center;
}
.input-group { position:relative; display:flex; align-items:center; }
.input-group .input { padding-right:38px; }
.input-group .btn-icon { position:absolute; right:2px; width:30px; height:30px; }
.form-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); gap:var(--s-4); }
.form-grid .span-2 { grid-column:1/-1; }

.switch { display:inline-flex; align-items:center; gap:9px; cursor:pointer; user-select:none; }
.switch input { position:absolute; opacity:0; width:0; height:0; }
.switch-track {
  width:36px; height:20px; border-radius:var(--r-pill); flex:none;
  background:var(--border-strong); position:relative;
  transition:background var(--base) var(--ease);
}
.switch-track::after {
  content:""; position:absolute; top:2px; left:2px; width:16px; height:16px;
  border-radius:50%; background:#fff; box-shadow:0 1px 2px rgba(0,0,0,.3);
  transition:transform var(--base) var(--ease);
}
.switch input:checked + .switch-track { background:var(--accent); }
.switch input:checked + .switch-track::after { transform:translateX(16px); }
.switch input:focus-visible + .switch-track { box-shadow:0 0 0 3px var(--accent-ring); }
.switch input:disabled + .switch-track { opacity:.5; }
.switch-label { font-size:.8125rem; color:var(--text-2); }

.check { display:inline-flex; align-items:center; gap:8px; cursor:pointer; font-size:.8125rem; }
.check input { appearance:none; width:16px; height:16px; flex:none; border:1.5px solid var(--border-strong); border-radius:5px; background:var(--surface); transition:all var(--base) var(--ease); }
.check input:checked { background:var(--accent); border-color:var(--accent); background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'><path d='m20 6-11 11-5-5'/></svg>"); background-size:11px; background-position:center; background-repeat:no-repeat; }
.check input:focus-visible { box-shadow:0 0 0 3px var(--accent-ring); }

.range { width:100%; appearance:none; height:4px; border-radius:99px; background:var(--border-strong); }
.range::-webkit-slider-thumb { appearance:none; width:16px; height:16px; border-radius:50%; background:var(--accent); border:2px solid var(--surface); box-shadow:var(--shadow-1); cursor:pointer; }
.range::-moz-range-thumb { width:14px; height:14px; border:2px solid var(--surface); border-radius:50%; background:var(--accent); cursor:pointer; }

/* --- badges --- */
.badge {
  display:inline-flex; align-items:center; gap:5px;
  padding:2px 8px; border-radius:var(--r-pill);
  font-size:.6875rem; font-weight:600; line-height:1.6; white-space:nowrap;
  background:var(--surface-3); color:var(--text-2); border:1px solid transparent;
}
.badge .ico { width:12px; height:12px; }
.badge-accent { background:var(--accent-soft); color:var(--accent-text); }
.badge-violet { background:var(--violet-soft); color:var(--violet-text); }
.badge-success { background:var(--success-soft); color:var(--success); }
.badge-warning { background:var(--warning-soft); color:var(--warning); }
.badge-danger  { background:var(--danger-soft);  color:var(--danger); }
.badge-info    { background:var(--info-soft);    color:var(--info); }
.badge-outline { background:transparent; border-color:var(--border-strong); color:var(--text-2); }

.dot { width:8px; height:8px; border-radius:50%; flex:none; background:var(--text-3); }
.dot-success { background:var(--success); box-shadow:0 0 0 3px var(--success-soft); }
.dot-danger  { background:var(--danger);  box-shadow:0 0 0 3px var(--danger-soft); }
.dot-warning { background:var(--warning); box-shadow:0 0 0 3px var(--warning-soft); }
.dot-idle    { background:var(--text-3);  box-shadow:0 0 0 3px var(--surface-3); }
.dot-live { position:relative; }
.dot-live::after {
  content:""; position:absolute; inset:-3px; border-radius:50%;
  border:1px solid currentColor; opacity:.6; animation:pulse 2s var(--ease) infinite;
}
@keyframes pulse { 0%{transform:scale(.7);opacity:.7} 70%{transform:scale(1.5);opacity:0} 100%{opacity:0} }

.conn {
  display:inline-flex; align-items:center; gap:7px; height:28px; padding:0 10px;
  border-radius:var(--r-pill); background:var(--surface-3);
  font-size:.6875rem; font-weight:600; color:var(--text-2);
}
.conn[data-state="online"] { background:var(--success-soft); color:var(--success); }
.conn[data-state="offline"] { background:var(--danger-soft); color:var(--danger); }
.conn[data-state="connecting"] { background:var(--warning-soft); color:var(--warning); }

.avatar {
  width:34px; height:34px; flex:none; border-radius:50%;
  display:grid; place-items:center;
  font-size:.75rem; font-weight:650; letter-spacing:.01em;
  background:var(--accent-soft); color:var(--accent-text);
  text-transform:uppercase;
}
.avatar-sm { width:28px; height:28px; font-size:.6875rem; }
.avatar-lg { width:42px; height:42px; font-size:.875rem; }
.avatar-group { background:var(--violet-soft); color:var(--violet-text); border-radius:12px; }

/* --- user menu / dropdown --- */
.user-btn {
  display:flex; align-items:center; gap:8px; height:38px; padding:0 8px 0 4px;
  border-radius:var(--r-md); transition:background var(--base) var(--ease);
}
.user-btn:hover { background:var(--surface-3); }
.user-btn .ico { width:14px; height:14px; color:var(--text-3); }
.user-btn .avatar { width:28px; height:28px; font-size:.6875rem; }
.user-meta { display:flex; flex-direction:column; align-items:flex-start; line-height:1.2; }
.user-meta strong { font-size:.75rem; font-weight:600; }
.user-meta small { font-size:.625rem; color:var(--text-3); text-transform:capitalize; }

.menu { position:relative; }
.dropdown {
  position:absolute; right:0; top:calc(100% + 6px); z-index:80; min-width:208px;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  box-shadow:var(--shadow-3); padding:5px; animation:pop var(--base) var(--ease);
}
.dropdown.to-left { right:auto; left:0; }
@keyframes pop { from { opacity:0; transform:translateY(-4px) scale(.98); } }
.dropdown-head { padding:8px 10px 6px; display:flex; flex-direction:column; line-height:1.3; }
.dropdown-head strong { font-size:.8125rem; }
.dropdown-sep { height:1px; background:var(--border-soft); margin:4px 0; }
.dropdown-item {
  display:flex; align-items:center; gap:9px; width:100%; text-align:left;
  padding:7px 10px; border-radius:var(--r-sm); font-size:.8125rem; color:var(--text);
  transition:background var(--base) var(--ease);
}
.dropdown-item:hover { background:var(--surface-3); text-decoration:none; }
.dropdown-item .ico { width:16px; height:16px; color:var(--text-3); }
.dropdown-item.is-danger { color:var(--danger); }
.dropdown-item.is-danger .ico { color:var(--danger); }
.dropdown-item.is-danger:hover { background:var(--danger-soft); }

/* --- searchable select (combobox over a native <select>) --- */
/* The native control stays in the DOM and keeps owning the value; it is only
   taken out of sight. It is moved out of flow with position:fixed rather than
   display:none, for two reasons: the page scripts toggle some of these selects
   with the hidden attribute and [hidden] must stay the one thing that decides
   visibility, and a fixed element reports offsetParent === null, which is what
   keeps the modal focus trap from landing on an invisible control. */
.cbx-native {
  position:fixed; top:0; left:0; width:1px; height:1px; min-height:0;
  margin:0; padding:0; border:0; opacity:0; pointer-events:none; z-index:-1;
  clip-path:inset(50%); overflow:hidden; background:none;
}
/* The trigger wears .select as well, so height, radius, border, background,
   focus ring and chevron are the native ones — forms keep their shape. */
.cbx-trigger { display:flex; align-items:center; gap:8px; text-align:left; }
.cbx-trigger .cbx-value { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cbx-trigger.is-empty .cbx-value { color:var(--text-3); }

.cbx-pop {
  position:fixed; left:0; top:0; z-index:160;
  display:flex; flex-direction:column; min-width:180px;
  max-width:calc(100vw - 16px); max-height:340px; overflow:hidden;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  box-shadow:var(--shadow-3); padding:5px; animation:pop var(--base) var(--ease);
}
.cbx-search { position:relative; flex:none; padding:2px 2px 6px; }
.cbx-search > .ico {
  position:absolute; left:11px; top:calc(50% - 3px); transform:translateY(-50%);
  width:15px; height:15px; color:var(--text-3); pointer-events:none;
}
.cbx-input {
  width:100%; height:32px; padding:0 10px 0 32px;
  background:var(--surface-3); border:1px solid transparent; border-radius:var(--r-sm);
  color:var(--text); font-size:.8125rem;
}
.cbx-input::placeholder { color:var(--text-3); }
.cbx-input:focus { outline:none; background:var(--surface); border-color:var(--border-strong); box-shadow:0 0 0 3px var(--accent-ring); }
.cbx-list { flex:1 1 auto; min-height:0; overflow-y:auto; overscroll-behavior:contain; }
.cbx-group {
  padding:8px 10px 4px; font-size:.625rem; font-weight:700; letter-spacing:.09em;
  text-transform:uppercase; color:var(--text-3);
}
.cbx-opt {
  display:flex; align-items:center; gap:8px; padding:7px 10px;
  border-radius:var(--r-sm); font-size:.8125rem; color:var(--text); cursor:pointer;
}
.cbx-opt .cbx-txt { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cbx-opt .ico { width:15px; height:15px; flex:none; color:var(--accent); }
.cbx-opt mark { background:var(--accent-soft); color:var(--accent-text); border-radius:3px; padding:0 1px; font-weight:650; }
.cbx-opt.is-active { background:var(--surface-3); }
.cbx-opt[aria-selected="true"] { color:var(--accent-text); font-weight:600; }
.cbx-opt[aria-disabled="true"] { color:var(--text-3); cursor:not-allowed; }
.cbx-opt[aria-disabled="true"].is-active { background:transparent; }
.cbx-note { padding:12px 10px; font-size:.75rem; color:var(--text-3); text-align:center; }

/* --- table --- */
.table-wrap { overflow-x:auto; border-radius:0 0 var(--r-xl) var(--r-xl); }
table.table { font-size:.8125rem; min-width:620px; }
table.table thead th {
  position:sticky; top:0; z-index:2;
  background:var(--surface-2); color:var(--text-3);
  font-size:.6875rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  text-align:left; padding:9px var(--s-4); white-space:nowrap;
  border-bottom:1px solid var(--border);
}
table.table tbody td { padding:11px var(--s-4); border-bottom:1px solid var(--border-soft); vertical-align:middle; }
table.table tbody tr { transition:background var(--fast) var(--ease); }
table.table tbody tr:hover { background:var(--surface-2); }
table.table tbody tr:last-child td { border-bottom:0; }
table.table td.right,table.table th.right { text-align:right; }
table.table td.actions { white-space:nowrap; text-align:right; }
.cell-main { font-weight:600; }
.cell-sub { font-size:.6875rem; color:var(--text-3); }

/* A cell's content decides its width under table-layout:auto, so one schedule
   carrying a 120-character Cacti URL or a long caption used to stretch its
   column and knock every other column out of line. `truncate` alone cannot
   prevent that inside a table: the cell still asks for the full intrinsic
   width of its nowrap text, so the ceiling has to be stated. These are upper
   bounds, not fixed widths — short values are unaffected, and the columns stay
   aligned however long the content gets. */
table.table .cell-main { max-width:30ch; }
/* Tindak Lanjut: long prose cells clamp to two lines; the row click opens the full text */
table.table .wrap2 { display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; white-space:normal; max-width:34ch; line-height:1.4; }
/* Tindak Lanjut: fixed column widths and one line per cell. Long text is cut
   with an ellipsis (full text on hover and in the row's detail dialog), so
   every row has the same height and the columns never drift. */
table.table .trunc { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:100%; }
body[data-page="followups"] table.table,
body[data-page="prospects"] table.table,
body[data-page="chat_report"] table.table { table-layout:fixed; width:100%; min-width:1100px; }
body[data-page="prospects"] table.table tbody tr, body[data-page="chat_report"] table.table tbody tr { cursor:pointer; }
body[data-page="prospects"] table.table td, body[data-page="chat_report"] table.table td { overflow:hidden; vertical-align:middle; }
body[data-page="followups"] table.table tbody tr { cursor:pointer; }
body[data-page="followups"] table.table td { overflow:hidden; vertical-align:middle; }
/* Prospek Pelanggan: the column widths this table never had.
   
   It is table-layout:fixed, and a fixed table with no declared widths splits
   itself evenly — seven columns at 14.3% each, which gave the Aksi column
   ~157px to hold one 28px icon button while the address and the needs columns
   were truncating. The percentages below spend the width where the text is;
   Aksi gets the floor it needs for the button and nothing more, the same way
   the Tindak Lanjut table already does it. */
body[data-page="prospects"] table.table th:nth-child(1), body[data-page="prospects"] table.table td:nth-child(1) { width:11%; }
body[data-page="prospects"] table.table th:nth-child(2), body[data-page="prospects"] table.table td:nth-child(2) { width:16%; }
body[data-page="prospects"] table.table th:nth-child(3), body[data-page="prospects"] table.table td:nth-child(3) { width:20%; }
body[data-page="prospects"] table.table th:nth-child(4), body[data-page="prospects"] table.table td:nth-child(4) { width:12%; }
body[data-page="prospects"] table.table th:nth-child(5), body[data-page="prospects"] table.table td:nth-child(5) { width:26%; }
body[data-page="prospects"] table.table th:nth-child(6), body[data-page="prospects"] table.table td:nth-child(6) { width:9%; }
body[data-page="prospects"] table.table th:nth-child(7), body[data-page="prospects"] table.table td:nth-child(7) { width:6%; min-width:60px; }
body[data-page="followups"] table.table th:nth-child(1), body[data-page="followups"] table.table td:nth-child(1) { width:9%; }
body[data-page="followups"] table.table th:nth-child(2), body[data-page="followups"] table.table td:nth-child(2) { width:13%; }
body[data-page="followups"] table.table th:nth-child(3), body[data-page="followups"] table.table td:nth-child(3) { width:13%; }
body[data-page="followups"] table.table th:nth-child(4), body[data-page="followups"] table.table td:nth-child(4) { width:12%; }
body[data-page="followups"] table.table th:nth-child(5), body[data-page="followups"] table.table td:nth-child(5) { width:15%; }
body[data-page="followups"] table.table th:nth-child(6), body[data-page="followups"] table.table td:nth-child(6) { width:12%; }
body[data-page="followups"] table.table th:nth-child(7), body[data-page="followups"] table.table td:nth-child(7) { width:12%; }
body[data-page="followups"] table.table th:nth-child(8), body[data-page="followups"] table.table td:nth-child(8) { width:10%; }
body[data-page="followups"] table.table th:nth-child(9), body[data-page="followups"] table.table td:nth-child(9) { width:4%; min-width:44px; }
/* Consecutive blocks on a page keep one rhythm: stat grid, note, panel
   grid, table card. Grids space their own children; this spaces the grids. */
.main > section + section, .main > section + p, .main > p + section,
.main > .filterbar + section, .main > section + .filterbar { margin-top:var(--s-4); }

/* --- compact filter bar ---
   One row that wraps: a search box that takes the slack, short selects and
   date fields, a reset icon. No stacked labels: the controls carry their own
   placeholder and aria-label, which is what keeps the bar one line tall. */
.filterbar {
  display:flex; align-items:center; gap:8px; flex-wrap:wrap;
  padding:10px var(--s-4); border-bottom:1px solid var(--border-soft);
}
.filterbar.is-standalone { border:1px solid var(--border); border-radius:var(--r-xl); background:var(--surface); box-shadow:var(--shadow-1); }
.filterbar .input, .filterbar .select { width:auto; min-height:32px; padding-top:5px; padding-bottom:5px; font-size:.8125rem; }
.filterbar .fb-q { flex:1 1 220px; min-width:160px; }
.filterbar .select { min-width:9.5rem; }
.filterbar .fb-date { display:inline-flex; align-items:center; gap:6px; }
.filterbar .fb-date > span { font-size:.6875rem; color:var(--text-3); white-space:nowrap; }
.filterbar .fb-date .input { width:9.75rem; }
.filterbar .fb-sep { width:1px; height:22px; background:var(--border-soft); margin:0 2px; }
.filterbar .btn-icon { flex:none; }
.filterbar .fb-right { margin-left:auto; display:inline-flex; gap:8px; align-items:center; }
@media (max-width:640px) { .filterbar .fb-right { margin-left:0; } .filterbar .fb-date .input { width:8.5rem; } }
.fu-pager { flex-wrap:wrap; }
.fu-pager .btn { min-width:32px; padding-left:8px; padding-right:8px; font-variant-numeric:tabular-nums; }
.fu-ellipsis { padding:0 4px; color:var(--text-3); }
@media (max-width:640px) { .fu-filters .fu-q { grid-column:1/-1; } }
.mt-areas { display:flex; flex-wrap:wrap; gap:4px; max-width:30ch; }
.mt-areas .badge small { opacity:.7; font-weight:600; text-transform:uppercase; font-size:.5625rem; }
.mt-selected { max-width:none; min-height:28px; padding:6px 8px; border:1px dashed var(--border-strong); border-radius:var(--r-md); }
.chip-x { border:0; background:transparent; color:inherit; cursor:pointer; margin-left:4px; padding:0 2px; font-size:.875rem; line-height:1; }
.mt-picker { position:relative; }
.mt-picklist { margin-top:4px; max-height:220px; overflow-y:auto; border:1px solid var(--border); border-radius:var(--r-md); padding:4px 8px; background:var(--surface); box-shadow:var(--shadow-2); }
.mt-picklist[hidden] { display:none; }
.mt-pick-head { font-size:.625rem; font-weight:700; letter-spacing:.04em; text-transform:uppercase; color:var(--text-3); margin:8px 0 2px; }
.mt-pick { display:flex; align-items:center; gap:8px; padding:4px 2px; font-size:.8125rem; cursor:pointer; }
.mt-pick:hover { background:var(--surface-3); border-radius:var(--r-sm); }
.mt-pick-name { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
body[data-page="maintenance"] table.table { min-width:900px; }
.mb-shot { display:block; max-width:100%; max-height:360px; width:auto; border-radius:var(--r-md); border:1px solid var(--border); margin-top:8px; }
.mb-cfg { margin-top:var(--s-3); }
.mb-cfg .card-flat, .card-flat { padding:var(--s-3); box-shadow:none; }
.card-flat h4 { font-size:.8125rem; margin-bottom:var(--s-2); }
.mb-wifi + .mb-wifi { margin-top:var(--s-2); padding-top:var(--s-2); border-top:1px dashed var(--border-soft); }
.mb-gallery { display:grid; grid-template-columns:repeat(auto-fill, minmax(160px, 1fr)); gap:10px; margin-top:8px; }
.mb-thumb { display:flex; flex-direction:column; gap:4px; color:var(--text-2); }
.mb-thumb img { width:100%; aspect-ratio:4/3; object-fit:cover; object-position:top; border:1px solid var(--border); border-radius:var(--r-md); background:var(--surface-2); }
.mb-pages { margin-top:6px; display:flex; flex-direction:column; gap:2px; max-height:200px; overflow:auto; }
.gap-xs { gap:4px; }
.mb-text { max-height:280px; overflow:auto; white-space:pre-wrap; background:var(--surface-2); border:1px solid var(--border-soft); border-radius:var(--r-sm); padding:8px; margin-top:6px; }
.mt { margin-top:var(--s-3); }
.info-list { display:grid; grid-template-columns:repeat(auto-fit, minmax(240px, 1fr)); gap:6px 18px; margin:0; }
table.table .cell-sub { max-width:38ch; }
@media (max-width:1279px) {
  table.table .cell-main { max-width:22ch; }
  table.table .cell-sub { max-width:26ch; }
}

/* Auto layout hands width to whichever cell demands it, and a nowrap URL
   demands far more than a name that can wrap — so the schedule name was being
   squeezed to a third of the width of the address beside it. These give the
   name a floor and the kind a ceiling, putting the columns back in order of
   importance instead of in order of how unbreakable their text is. */
/* min and max are deliberately the same value: a column whose width follows
   its content moves every time a schedule with a longer URL or a different
   target is added, and the whole table re-flows around it. Pinning the three
   free-text columns keeps the layout identical whatever the rows contain. */
table.table td.col-name   { min-width:13rem; max-width:13rem; }
table.table td.col-kind   { min-width:14rem; max-width:14rem; }
table.table td.col-target { min-width:13rem; max-width:13rem; }
@media (max-width:1279px) {
  table.table td.col-name   { min-width:10rem; max-width:10rem; }
  table.table td.col-kind   { min-width:11rem; max-width:11rem; }
  table.table td.col-target { min-width:10rem; max-width:10rem; }
}

/* --- paged table (WA.tableView) --- */
/* The filter box and the pager are siblings of the scrolling table box, never
   inside it: table.table has a 620px floor, so at phone width the box scrolls
   sideways and anything inside it would scroll out of reach with the rows.
   Pinned column widths are untouched — the component renders the same
   table.table with the same cells, only ten of them at a time. */
.tv { display:flex; flex-direction:column; min-width:0; }
.tv-bar {
  display:flex; align-items:center; gap:var(--s-2); flex-wrap:wrap;
  padding:var(--s-3) var(--s-4); border-bottom:1px solid var(--border-soft);
}
.tv-bar .tv-q { flex:1 1 200px; max-width:340px; min-width:0; }
/* the rounded bottom corners belong to the footer now */
.tv > .table-wrap { border-radius:0; }
.tv-foot {
  display:flex; align-items:center; justify-content:space-between;
  gap:var(--s-3) var(--s-4); flex-wrap:wrap;
  padding:var(--s-3) var(--s-4); border-top:1px solid var(--border-soft);
  background:var(--surface-2); border-radius:0 0 var(--r-xl) var(--r-xl);
}
.tv-size { display:flex; align-items:center; gap:var(--s-2); min-width:0; }
.tv-size-label { font-size:.75rem; color:var(--text-3); white-space:nowrap; }
/* .select is width:100% for form fields; here it sizes to its two digits.
   The combobox trigger WA.select puts beside it inherits the same classes. */
.tv-size .select {
  width:auto; min-width:4.5rem; min-height:28px;
  padding-top:3px; padding-bottom:3px; font-size:.75rem;
}
.tv-count { font-size:.75rem; color:var(--text-3); font-variant-numeric:tabular-nums; }
.tv-nav { display:flex; align-items:center; gap:6px; }

/* --- tabs --- */
.tabs { display:flex; gap:2px; border-bottom:1px solid var(--border); margin-bottom:var(--s-5); overflow-x:auto; }
.tab {
  position:relative; padding:9px 14px; font-size:.8125rem; font-weight:560;
  color:var(--text-2); white-space:nowrap; border-radius:var(--r-sm) var(--r-sm) 0 0;
  transition:color var(--base) var(--ease), background var(--base) var(--ease);
}
.tab:hover { color:var(--text); background:var(--surface-2); }
.tab[aria-selected="true"] { color:var(--accent-text); }
.tab[aria-selected="true"]::after {
  content:""; position:absolute; left:10px; right:10px; bottom:-1px; height:2px;
  border-radius:2px 2px 0 0; background:var(--accent);
}
.tabpanel[hidden] { display:none; }

.chips { display:flex; gap:6px; flex-wrap:wrap; }
.chip {
  padding:4px 10px; border-radius:var(--r-pill); font-size:.75rem; font-weight:550;
  background:var(--surface-3); color:var(--text-2); border:1px solid transparent;
  transition:all var(--base) var(--ease);
}
.chip:hover { color:var(--text); border-color:var(--border-strong); }
.chip[aria-pressed="true"] { background:var(--accent); color:var(--accent-fg); border-color:transparent; }

/* --- multi-target picker (Penjadwalan) --- */
/* One schedule reaches several groups, so the destinations are chosen one at
   a time and shown as removable chips. The whole block has to survive a group
   called "Pelanggan Korporat Jakarta Selatan — Batch 3": every element below
   carries min-width:0 and the name truncates, or one long chip would push the
   modal body into sideways scrolling at phone width. */
.target-add { display:flex; flex-wrap:wrap; align-items:center; gap:var(--s-2); min-width:0; }
/* .select is width:100%; inside the row it may shrink but must still be the
   wide one of the two, so it grows and the Tambah button does not. */
.target-add > .select, .target-add > .input { flex:1 1 12rem; min-width:0; }
.target-add > .btn { flex:0 0 auto; }
.target-chips {
  display:flex; flex-wrap:wrap; gap:6px; min-width:0;
  margin:var(--s-2) 0 0; padding:0; list-style:none;
}
.target-chip {
  display:inline-flex; align-items:center; gap:4px; min-width:0; max-width:100%;
  padding:3px 3px 3px 10px; border-radius:var(--r-pill);
  font-size:.75rem; font-weight:550;
  background:var(--surface-3); color:var(--text-2); border:1px solid var(--border);
}
/* The cap is in rem, not per cent. A nowrap, ellipsised name still reports
   its whole unwrapped length as its min-content width, and percentages are
   ignored while that is computed -- so one 63-character group name was
   widening the modal card itself from 390px to 485px at phone width, pushing
   its own Simpan button off the screen. An absolute ceiling is what the
   intrinsic pass actually honours. The full name is in the chip's tooltip. */
.target-chip-name {
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; max-width:16rem;
}
@media (max-width:480px) { .target-chip-name { max-width:11rem; } }
/* The memory notes in the chat room reuse the chip shape, but the info pane is
   much narrower than the modal those caps were measured in. Without a tighter
   ceiling here one 160-character note widens the pane itself, for the same
   intrinsic-width reason documented above. */
.pane-info .target-chip-name { max-width:10rem; }
.target-chip-x {
  flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center;
  width:18px; height:18px; border-radius:50%; font-size:.875rem; line-height:1;
  color:var(--text-3); transition:background var(--base) var(--ease), color var(--base) var(--ease);
}
.target-chip-x:hover { background:var(--danger-soft); color:var(--danger); }
.target-chip-x:focus-visible { outline:2px solid var(--accent); outline-offset:1px; }

/* --- modal --- */
.modal-root { position:fixed; inset:0; z-index:120; display:grid; place-items:center; padding:var(--s-4); }
.modal-backdrop { position:absolute; inset:0; background:var(--overlay); backdrop-filter:blur(3px); animation:fade var(--base) var(--ease); }
@keyframes fade { from { opacity:0; } }
.modal-card {
  position:relative; z-index:1; width:min(640px,100%); max-height:88dvh;
  display:flex; flex-direction:column;
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-2xl); box-shadow:var(--shadow-3);
  animation:rise var(--slow) var(--ease);
}
.modal-card.is-wide { width:min(880px,100%); }
.modal-card.is-narrow { width:min(440px,100%); }
.modal-card.is-alarm { border-color:var(--danger); box-shadow:0 0 0 4px var(--danger-soft), var(--shadow-3); }
.modal-card.is-alarm .modal-head h2 { color:var(--danger); }
.dev-alarm { text-align:center; padding:var(--s-4) var(--s-3) var(--s-2); }
.dev-alarm-ico { width:72px; height:72px; margin:0 auto var(--s-4); border-radius:50%; display:grid; place-items:center;
  background:var(--danger-soft); color:var(--danger); animation:alarmPulse 1.6s ease-in-out infinite; }
.dev-alarm-ico .ico { width:36px; height:36px; }
.dev-alarm h3 { font-size:1.25rem; margin-bottom:var(--s-2); }
.dev-alarm > p { max-width:56ch; margin:0 auto var(--s-4); color:var(--text-2); }
.dev-alarm-list { list-style:none; display:flex; flex-direction:column; gap:8px; max-width:520px; margin:0 auto var(--s-4); text-align:left; }
.dev-alarm-item { display:flex; align-items:center; gap:12px; padding:10px 14px; border:1px solid var(--border); border-radius:var(--r-lg); background:var(--surface-2); }
.dev-alarm-item .dot { width:10px; height:10px; }
@keyframes alarmPulse { 0%,100% { box-shadow:0 0 0 0 var(--danger-soft); } 50% { box-shadow:0 0 0 12px transparent; } }
@keyframes rise { from { opacity:0; transform:translateY(12px) scale(.985); } }
.modal-head { display:flex; align-items:center; justify-content:space-between; gap:var(--s-3); padding:var(--s-4) var(--s-5); border-bottom:1px solid var(--border-soft); flex:none; }
.modal-head h2 { font-size:.9375rem; }
.modal-body { padding:var(--s-5); overflow-y:auto; flex:1; }
.modal-foot { display:flex; align-items:center; justify-content:flex-end; gap:var(--s-2); padding:var(--s-3) var(--s-5); border-top:1px solid var(--border-soft); background:var(--surface-2); border-radius:0 0 var(--r-2xl) var(--r-2xl); flex:none; flex-wrap:wrap; }
.modal-foot .spread { margin-right:auto; }

/* --- toast --- */
.toast-stack {
  position:fixed; z-index:200; right:var(--s-4); bottom:var(--s-4);
  display:flex; flex-direction:column; gap:var(--s-2); width:min(360px,calc(100vw - 32px));
  pointer-events:none;
}
.toast {
  pointer-events:auto; display:flex; align-items:flex-start; gap:10px;
  padding:11px 13px; border-radius:var(--r-lg);
  background:var(--surface); border:1px solid var(--border); box-shadow:var(--shadow-3);
  font-size:.8125rem; animation:slidein var(--slow) var(--ease);
  border-left:3px solid var(--text-3);
}
@keyframes slidein { from { opacity:0; transform:translateX(16px); } }
.toast.is-out { opacity:0; transform:translateX(16px); transition:all var(--slow) var(--ease); }
.toast .ico { width:16px; height:16px; margin-top:1px; flex:none; }
.toast > * { min-width:0; overflow-wrap:anywhere; }
.toast-success { border-left-color:var(--success); } .toast-success .ico { color:var(--success); }
.toast-error   { border-left-color:var(--danger); }  .toast-error .ico { color:var(--danger); }
.toast-warn    { border-left-color:var(--warning); } .toast-warn .ico { color:var(--warning); }
.toast-info    { border-left-color:var(--info); }    .toast-info .ico { color:var(--info); }

/* --- alert --- */
.alert {
  display:flex; align-items:flex-start; gap:10px;
  padding:11px 14px; border-radius:var(--r-lg); font-size:.8125rem;
  border:1px solid var(--border); background:var(--surface-2); margin-bottom:var(--s-4);
}
.alert .ico { width:17px; height:17px; flex:none; margin-top:1px; }
.alert-success { background:var(--success-soft); border-color:transparent; color:var(--success); }
.alert-danger  { background:var(--danger-soft);  border-color:transparent; color:var(--danger); }
.alert-warning { background:var(--warning-soft); border-color:transparent; color:var(--warning); }
.alert-info    { background:var(--info-soft);    border-color:transparent; color:var(--info); }

/* --- empty / skeleton --- */
.empty { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--s-2); text-align:center; padding:var(--s-7) var(--s-4); }
.empty-art { width:52px; height:52px; display:grid; place-items:center; border-radius:16px; background:var(--surface-3); color:var(--text-3); margin-bottom:var(--s-1); }
.empty-art .ico { width:24px; height:24px; }
.empty h3 { font-size:.875rem; }
.empty p { font-size:.8125rem; color:var(--text-3); max-width:40ch; }
.empty .btn { margin-top:var(--s-3); }

.skeleton { position:relative; overflow:hidden; background:var(--surface-3); border-radius:var(--r-sm); }
.skeleton::after {
  content:""; position:absolute; inset:0; transform:translateX(-100%);
  background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--surface) 70%,transparent),transparent);
  animation:shimmer 1.3s infinite;
}
@keyframes shimmer { to { transform:translateX(100%); } }
.sk-line { height:11px; margin-bottom:8px; }
.sk-line.w-40 { width:40%; } .sk-line.w-60 { width:60%; } .sk-line.w-80 { width:80%; }
.sk-card { height:96px; border-radius:var(--r-xl); }
.sk-row { height:44px; margin-bottom:6px; border-radius:var(--r-md); }

/* --- tooltip --- */
[data-tip] { position:relative; }
[data-tip]::after {
  content:attr(data-tip); position:absolute; bottom:calc(100% + 7px); left:50%;
  transform:translateX(-50%) translateY(3px);
  background:var(--n-900); color:#fff; font-size:.6875rem; font-weight:500;
  padding:4px 8px; border-radius:var(--r-xs); white-space:nowrap; pointer-events:none;
  opacity:0; transition:all var(--base) var(--ease); z-index:90;
}
:root[data-theme="dark"] [data-tip]::after { background:var(--n-700); }
[data-tip]:hover::after,[data-tip]:focus-visible::after { opacity:1; transform:translateX(-50%) translateY(0); }

/* --- code --- */
pre.code {
  background:var(--surface-sunk); border:1px solid var(--border);
  border-radius:var(--r-md); padding:12px 14px; overflow-x:auto;
  font-size:.75rem; line-height:1.65; color:var(--text-2);
  white-space:pre; tab-size:2;
}
code.inline { background:var(--surface-3); border-radius:5px; padding:1px 5px; font-size:.75em; color:var(--accent-text); }
.key-reveal { font-family:var(--mono); font-size:.875rem; word-break:break-all; background:var(--surface-sunk); border:1px dashed var(--border-strong); border-radius:var(--r-md); padding:12px; }

/* --- charts --- */
.chart { width:100%; display:block; overflow:visible; }
.chart text { font-family:var(--font); font-size:10px; fill:var(--chart-axis); }
.chart .grid-line { stroke:var(--chart-grid); stroke-width:1; shape-rendering:crispEdges; }
.chart .bar { transition:opacity var(--base) var(--ease); }
.chart .hit:hover ~ .bar,.chart g:hover > .bar { opacity:.85; }
.chart-legend { display:flex; gap:var(--s-4); align-items:center; font-size:.75rem; color:var(--text-2); }
.chart-legend span { display:inline-flex; align-items:center; gap:6px; }
.chart-legend i { width:9px; height:9px; border-radius:3px; display:inline-block; background:var(--text-3); }
.chart-legend i[data-legend="in"]  { background:var(--chart-in); }
.chart-legend i[data-legend="out"] { background:var(--chart-out); }
/* Donut pies on the chat report (hand-rolled SVG; palette --cat-1..8). */
.grid-pies { grid-template-columns:repeat(auto-fit, minmax(230px, 1fr)); }
.pie-wrap { display:flex; align-items:center; gap:var(--s-4); flex-wrap:wrap; }
.pie-svg { width:120px; height:120px; flex:0 0 auto; }
.pie-slice { transition:opacity var(--base) var(--ease); }
.pie-svg:hover .pie-slice { opacity:.45; }
.pie-svg .pie-slice:hover { opacity:1; }
.pie-total { font-family:var(--font); font-weight:700; font-size:17px; fill:var(--text); }
.pie-total-sub { font-family:var(--font); font-size:8px; fill:var(--text-3); text-transform:uppercase; letter-spacing:.04em; }
.pie-legend { list-style:none; margin:0; padding:0; flex:1 1 130px; min-width:130px; display:flex; flex-direction:column; gap:5px; }
.pie-legend li { display:flex; align-items:center; gap:7px; font-size:.75rem; color:var(--text-2); }
.pie-legend li span { flex:1 1 auto; min-width:0; }
.pie-legend li b { flex:0 0 auto; color:var(--text); font-variant-numeric:tabular-nums; }
.pie-sw { width:10px; height:10px; border-radius:3px; flex:0 0 auto; display:inline-block; }
.offscreen { position:fixed; top:-1000px; left:-1000px; opacity:0; pointer-events:none; }
.chart-tip {
  position:absolute; z-index:40; pointer-events:none; left:var(--x,0); top:var(--y,0);
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-sm);
  box-shadow:var(--shadow-2); padding:7px 9px; font-size:.6875rem; line-height:1.5;
  white-space:nowrap; transform:translate(-50%,-115%); transition:opacity var(--fast) var(--ease);
}
.chart-box { position:relative; }
.hbar-row { display:grid; grid-template-columns:minmax(80px,30%) 1fr auto; gap:10px; align-items:center; font-size:.8125rem; padding:5px 0; }
.hbar-track { height:8px; border-radius:99px; background:var(--surface-3); overflow:hidden; }
.hbar-fill { height:100%; border-radius:99px; background:var(--accent); width:var(--w,0%); transition:width var(--slow) var(--ease); }

/* --- list rows --- */
.list { display:flex; flex-direction:column; }
.list-row {
  display:flex; align-items:center; gap:10px; padding:10px var(--s-4);
  border-bottom:1px solid var(--border-soft); font-size:.8125rem;
}
.tool-row { flex-wrap:wrap; row-gap:4px; }
.tool-row code { flex:0 0 11.5rem; }
.tool-row span { flex:1 1 14rem; min-width:0; }
.list-row:last-child { border-bottom:0; }
.list-row:hover { background:var(--surface-2); }
.feed { display:flex; flex-direction:column; gap:1px; }
.feed-item { display:flex; gap:10px; padding:9px var(--s-4); font-size:.8125rem; }
.feed-item:hover { background:var(--surface-2); }
.feed-dot { width:7px; height:7px; border-radius:50%; background:var(--accent); margin-top:6px; flex:none; }
.feed-body { min-width:0; }
.feed-body strong { font-weight:600; }
.feed-time { margin-left:auto; color:var(--text-3); font-size:.6875rem; white-space:nowrap; padding-left:8px; }

/* 5. PAGES ================================================================= */

/* --- login --- */
.auth {
  min-height:100dvh; display:grid; grid-template-columns:1fr;
  background:
    radial-gradient(900px 500px at 15% -10%, var(--accent-soft), transparent 60%),
    radial-gradient(700px 500px at 110% 110%, var(--violet-soft), transparent 60%),
    var(--bg);
}
.auth-panel { display:grid; place-items:center; padding:var(--s-5); }
.auth-card {
  width:min(400px,100%); background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-2xl); box-shadow:var(--shadow-3); padding:var(--s-6) var(--s-5);
}
.auth-brand { display:flex; align-items:center; gap:10px; margin-bottom:var(--s-5); }
.auth-brand img { width:38px; height:38px; }
.auth-brand strong { font-size:1.0625rem; letter-spacing:-.02em; display:block; }
.auth-brand small { font-size:.6875rem; color:var(--text-3); text-transform:uppercase; letter-spacing:.09em; }
.auth-card h1 { font-size:1.25rem; margin-bottom:4px; }
.auth-card > p.lead { font-size:.8125rem; color:var(--text-2); margin-bottom:var(--s-5); }
.auth-form { display:flex; flex-direction:column; gap:var(--s-4); }
.auth-foot { margin-top:var(--s-5); text-align:center; font-size:.6875rem; color:var(--text-3); }
.auth-aside { display:none; }
.auth-pitch { max-width:420px; }
.auth-pitch h2 { font-size:1.5rem; letter-spacing:-.025em; margin-bottom:var(--s-3); }
.auth-pitch > p { color:var(--text-2); font-size:.875rem; margin-bottom:var(--s-5); }
.pitch-list { display:flex; flex-direction:column; gap:var(--s-4); }
.pitch-item { display:flex; gap:12px; }
.pitch-ico { width:34px; height:34px; flex:none; border-radius:10px; display:grid; place-items:center; background:var(--surface); border:1px solid var(--border); color:var(--accent); box-shadow:var(--shadow-1); }
.pitch-item strong { display:block; font-size:.8125rem; }
.pitch-item p { font-size:.75rem; color:var(--text-2); }

/* --- inbox --- */
.inbox { position:relative; display:grid; grid-template-columns:320px minmax(0,1fr); height:100%; min-height:0; }
.inbox.show-info { grid-template-columns:320px minmax(0,1fr) 300px; }
.pane { display:flex; flex-direction:column; min-height:0; min-width:0; background:var(--surface); }
.pane-chats { border-right:1px solid var(--border); }
.pane-conv { background:var(--surface-2); }
.pane-info { border-left:1px solid var(--border); overflow-y:auto; }
.inbox-head { flex:none; padding:var(--s-3) var(--s-3) var(--s-2); border-bottom:1px solid var(--border-soft); display:flex; flex-direction:column; gap:var(--s-2); }
.chat-search { position:relative; }
.chat-search .ico { position:absolute; left:9px; top:50%; transform:translateY(-50%); color:var(--text-3); width:15px; height:15px; }
.chat-search input { padding-left:30px; height:32px; }
.chat-list { flex:1; overflow-y:auto; overscroll-behavior:contain; }
.chat-item {
  display:flex; gap:10px; width:100%; text-align:left; padding:10px var(--s-3);
  border-bottom:1px solid var(--border-soft); position:relative;
  transition:background var(--fast) var(--ease);
}
.chat-item:hover { background:var(--surface-2); }
.chat-item.is-active { background:var(--accent-soft); }
.chat-item.is-active::before { content:""; position:absolute; left:0; top:0; bottom:0; width:3px; background:var(--accent); }
.chat-item-body { flex:1; min-width:0; }
.chat-item-top { display:flex; align-items:baseline; gap:6px; }
.chat-item-name { font-size:.8125rem; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* The WhatsApp push name of a number nobody has registered yet. It rides
   beside the number instead of replacing it, and it is the first thing to give
   up space when the row is narrow: the number is what an operator dials and
   searches billing with, the nickname is only a hint about who is typing.
   flex-shrink is deliberately high for that reason, and the cap is absolute
   because a 40-character push name would otherwise push the clock off the
   row — the same intrinsic-width trap documented on .target-chip-name. */
.chat-item-alias {
  flex:0 1 auto; flex-shrink:6; min-width:0; max-width:9rem;
  font-size:.6875rem; color:var(--text-3);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.chat-item-time { margin-left:auto; font-size:.625rem; color:var(--text-3); white-space:nowrap; }
.chat-item-preview { font-size:.75rem; color:var(--text-3); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; margin-top:1px; }
.chat-item-tags { display:flex; align-items:center; gap:5px; margin-top:4px; }
.unread-pill { background:var(--accent); color:var(--accent-fg); border-radius:var(--r-pill); min-width:18px; height:18px; padding:0 5px; font-size:.625rem; font-weight:700; display:grid; place-items:center; }

.conv-head {
  flex:none; display:flex; align-items:center; gap:10px;
  padding:var(--s-2) var(--s-3); min-height:56px;
  background:var(--surface); border-bottom:1px solid var(--border);
}
.conv-title { min-width:0; }
.conv-title strong { display:block; font-size:.875rem; }
.conv-title small { display:block; font-size:.6875rem; color:var(--text-3); font-family:var(--mono); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.conv-title { flex:1 1 auto; }
.conv-actions { margin-left:auto; display:flex; align-items:center; gap:4px;
  flex:0 0 auto; max-width:100%; overflow-x:auto; scrollbar-width:none; }
.conv-actions::-webkit-scrollbar { display:none; }
.conv-actions > * { flex:none; }
.ai-toggle {
  display:inline-flex; align-items:center; gap:7px; height:30px; padding:0 10px;
  border-radius:var(--r-pill); background:var(--surface-3); font-size:.6875rem; font-weight:600;
  color:var(--text-2);
}
.ai-toggle[data-mode="auto"] { background:var(--violet-soft); color:var(--violet-text); }
.ai-toggle[data-mode="manual"] { background:var(--warning-soft); color:var(--warning); }
.ai-toggle[data-mode="off"] { background:var(--surface-3); color:var(--text-3); }

.thread { flex:1; overflow-y:auto; overscroll-behavior:contain; padding:var(--s-4) var(--s-4) var(--s-2); display:flex; flex-direction:column; gap:3px; }
.day-sep { align-self:center; margin:var(--s-3) 0 var(--s-2); font-size:.625rem; font-weight:650; letter-spacing:.05em; text-transform:uppercase; color:var(--text-3); background:var(--surface-3); border-radius:var(--r-pill); padding:3px 12px; }
.msg { display:flex; max-width:min(680px,78%); }
.msg.is-out { align-self:flex-end; justify-content:flex-end; }
.msg.is-in { align-self:flex-start; }
.bubble {
  position:relative; padding:8px 11px 6px; border-radius:var(--r-lg);
  background:var(--bubble-in); border:1px solid var(--bubble-in-br);
  font-size:.8125rem; line-height:1.5; box-shadow:var(--shadow-1); min-width:84px;
}
.msg.is-in .bubble { border-top-left-radius:4px; }
.msg.is-out .bubble { border-top-right-radius:4px; background:var(--bubble-out); border-color:var(--bubble-out-br); }
.msg[data-source="ai"] .bubble { background:var(--bubble-ai); border-color:var(--bubble-ai-br); }
.msg[data-source="rule"] .bubble { background:var(--info-soft); border-color:color-mix(in srgb,var(--info) 35%,transparent); }
.msg[data-source="scheduled"] .bubble { background:transparent; border-style:dashed; border-color:var(--border-strong); }
.msg[data-source="system"] { align-self:center; max-width:60ch; }
.msg[data-source="system"] .bubble { background:var(--surface-3); border-color:transparent; color:var(--text-3); font-size:.75rem; text-align:center; }
.bubble-sender { font-size:.6875rem; font-weight:700; color:var(--accent-text); margin-bottom:2px; }
.msg[data-source="ai"] .bubble-sender { color:var(--violet-text); }
.bubble-text { white-space:pre-wrap; word-break:break-word; }
.bubble-meta { display:flex; align-items:center; gap:5px; justify-content:flex-end; margin-top:3px; font-size:.625rem; color:var(--text-3); }
.bubble-meta .ico { width:13px; height:13px; }
.src-tag { display:inline-flex; align-items:center; gap:3px; font-size:.5625rem; font-weight:700; letter-spacing:.04em; text-transform:uppercase; padding:1px 5px; border-radius:var(--r-pill); }
.src-tag.ai { background:var(--violet); color:#fff; }
.src-tag.sched { background:var(--surface-3); color:var(--text-2); }
.src-tag.api { background:var(--info-soft); color:var(--info); }
.src-tag.rule { background:var(--info-soft); color:var(--info); }
.src-tag .ico { width:10px; height:10px; }
.src-tag.phone { background:var(--warning-soft); color:var(--warning); }
.src-tag.manual { background:var(--surface-3); color:var(--text-2); }
.msg[data-source="phone"] .bubble { border-color:color-mix(in srgb,var(--warning) 55%,transparent); }
.tick-read { color:var(--info); }
/* --- lampiran di gelembung ---
   Gambar dipajang sebatas lebar gelembung dan tingginya dibatasi, jadi foto
   potret tidak mengusir sisa percakapan. `width:fit-content` membuat kotaknya
   mengikuti gambar, bukan sebaliknya, sehingga tidak ada latar kosong di
   sisi gambar yang sempit. Semua baris berkas memakai min-width:0 supaya nama
   berkas yang panjang terpotong dengan elipsis, bukan melebarkan gelembung. */
.media-img {
  display:block; width:fit-content; max-width:100%; padding:0; border:0;
  background:none; border-radius:var(--r-md); overflow:hidden; line-height:0; cursor:zoom-in;
}
.media-img img {
  display:block; width:auto; height:auto; max-width:100%; max-height:260px;
  border-radius:var(--r-md); background:var(--surface-3);
}
.media-img:focus-visible { outline:none; box-shadow:0 0 0 3px var(--accent-ring); }
.media-img.is-sticker img { max-height:130px; background:transparent; }

.media-audio { display:block; width:248px; max-width:100%; }
.media-audio audio { display:block; width:100%; height:34px; }

.media-file {
  display:flex; align-items:center; gap:9px; min-width:0; max-width:100%;
  padding:7px 9px; border-radius:var(--r-md); background:var(--surface-3);
  border:1px solid var(--border-soft); color:var(--text);
}
a.media-file:hover { background:var(--surface-sunk); text-decoration:none; }
a.media-file:focus-visible { outline:none; box-shadow:0 0 0 3px var(--accent-ring); }
.media-file > .ico { width:17px; height:17px; flex:none; color:var(--text-2); }
.media-file-body { flex:1 1 auto; min-width:0; }
.media-file-name { display:block; font-size:.75rem; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.media-file-sub { display:block; margin-top:1px; font-size:.625rem; color:var(--text-3); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.media-file.is-gone { background:var(--warning-soft); border-color:color-mix(in srgb,var(--warning) 34%,transparent); }
.media-file.is-gone > .ico { color:var(--warning); }
.media-file.is-gone .media-file-name { color:var(--warning); }
/* Lampiran yang masih mungkin muncul sendiri (sedang diunduh, menunggu
   percobaan ulang) tidak diberi warna peringatan: tidak ada yang perlu
   dikerjakan operator, cukup menunggu. */
.media-file.is-waiting { background:var(--surface-3); border-style:dashed; }
.media-file.is-waiting > .ico { color:var(--text-3); }
/* keterangan "tidak tersedia" harus terbaca utuh, jadi boleh turun baris */
.media-file.is-gone .media-file-sub,
.media-file.is-waiting .media-file-sub { white-space:normal; }

/* --- video di gelembung ---
   Pemutar bawaan browser, dibatasi tingginya seperti gambar. Lebarnya tetap
   (bukan fit-content) karena sebelum metadata termuat video belum tahu
   ukurannya, dan kotak yang melompat lebar saat termuat mengganggu. Tombol
   perbesar menumpang di pojok, di luar jangkauan kontrol pemutar yang ada di
   bawah. */
.media-video { position:relative; display:block; width:288px; max-width:100%; }
.media-video video {
  display:block; width:100%; max-height:260px; border-radius:var(--r-md);
  background:#000; object-fit:contain;
}
.media-video-expand {
  position:absolute; top:6px; right:6px; width:28px; height:28px; padding:0; border:0;
  display:grid; place-items:center; border-radius:var(--r-md); cursor:pointer;
  background:rgba(0,0,0,.55); color:#fff; opacity:0; transition:opacity var(--base) var(--ease);
}
.media-video-expand .ico { width:15px; height:15px; }
.media-video:hover .media-video-expand,
.media-video:focus-within .media-video-expand { opacity:1; }
.media-video-expand:focus-visible { opacity:1; outline:none; box-shadow:0 0 0 3px var(--accent-ring); }
@media (hover:none) { .media-video-expand { opacity:1; } }
.media-video .media-file-sub { margin-top:3px; }
/* video yang berkasnya tidak ada: poster di atas keterangan */
.media-video-missing { display:block; width:288px; max-width:100%; }
.media-video-missing img { display:block; width:100%; max-height:180px; object-fit:cover; border-radius:var(--r-md) var(--r-md) 0 0; background:var(--surface-3); opacity:.75; }
.media-video-missing .media-file { border-radius:0 0 var(--r-md) var(--r-md); }

/* jarak keterangan (caption) di bawah lampiran */
.media-img + .bubble-text,
.media-file + .bubble-text,
.media-audio + .bubble-text,
.media-video + .bubble-text,
.media-video-missing + .bubble-text { margin-top:5px; }

/* pratinjau besar di dalam dialog */
.media-view { display:flex; flex-direction:column; align-items:center; gap:var(--s-2); min-width:0; }
.media-view img { max-width:100%; max-height:min(68dvh,700px); width:auto; height:auto; border-radius:var(--r-md); background:var(--surface-3); }
.media-view video { display:block; width:100%; max-width:100%; max-height:min(68dvh,700px); border-radius:var(--r-md); background:#000; object-fit:contain; }
.media-view p { font-size:.75rem; color:var(--text-2); max-width:100%; overflow-wrap:anywhere; text-align:center; }

.typing { display:flex; align-items:center; gap:4px; align-self:flex-start; padding:9px 13px; background:var(--bubble-in); border:1px solid var(--bubble-in-br); border-radius:var(--r-lg); border-top-left-radius:4px; }
.typing i { width:6px; height:6px; border-radius:50%; background:var(--text-3); animation:blink 1.3s infinite; }
.typing i:nth-child(2) { animation-delay:.18s; } .typing i:nth-child(3) { animation-delay:.36s; }
@keyframes blink { 0%,60%,100%{opacity:.25;transform:translateY(0)} 30%{opacity:1;transform:translateY(-2px)} }

.composer { flex:none; padding:var(--s-3); background:var(--surface); border-top:1px solid var(--border); }
.composer-box { display:flex; align-items:flex-end; gap:8px; background:var(--surface-2); border:1px solid var(--border-strong); border-radius:var(--r-xl); padding:6px 6px 6px 12px; transition:border-color var(--base) var(--ease), box-shadow var(--base) var(--ease); }
.composer-box:focus-within { border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-ring); }
.composer textarea { height:var(--ta-h,34px); min-height:34px; flex:1 1 auto; min-width:0;
  border:0; background:transparent; resize:none; outline:none; font-size:.8125rem;
  line-height:1.5; max-height:168px; padding:7px 0; }
.composer-attach {
  display:flex; align-items:center; gap:10px; margin-bottom:var(--s-2);
  padding:7px 9px; border:1px solid var(--border); border-radius:var(--r-lg);
  background:var(--surface-2); min-width:0;
}
.composer-attach-thumb {
  width:40px; height:40px; flex:none; border-radius:var(--r-sm); overflow:hidden;
  background:var(--surface-3); color:var(--text-2); display:grid; place-items:center;
}
.composer-attach-thumb img { width:100%; height:100%; object-fit:cover; display:block; }
.composer-attach-body { flex:1 1 auto; min-width:0; }
.composer-attach-name { display:block; font-size:.75rem; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.composer-attach-sub { display:block; font-size:.625rem; color:var(--text-3); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.upload-bar { margin-top:5px; height:4px; border-radius:var(--r-pill); background:var(--surface-3); overflow:hidden; }
.upload-bar > i { display:block; height:100%; width:0; background:var(--accent); transition:width var(--fast) linear; }
.composer-hint { display:flex; align-items:center; justify-content:space-between; gap:var(--s-3); margin-top:6px; font-size:.625rem; color:var(--text-3); }
.scroll-bottom { position:absolute; right:18px; bottom:96px; z-index:5; box-shadow:var(--shadow-2); background:var(--surface); border:1px solid var(--border); }
.pane-conv { position:relative; }

.info-section { padding:var(--s-4); border-bottom:1px solid var(--border-soft); }
.info-row { display:flex; justify-content:space-between; gap:var(--s-3); padding:4px 0; font-size:.75rem; }
.info-row dt { color:var(--text-3); flex:none; }
.info-row dd { text-align:right; min-width:0; overflow-wrap:anywhere; }

/* --- devices --- */
.device-card { display:flex; flex-direction:column; }
.device-top { display:flex; align-items:flex-start; gap:10px; padding:var(--s-4); }
.device-ico { width:40px; height:40px; border-radius:12px; display:grid; place-items:center; background:var(--surface-3); color:var(--text-2); flex:none; }
.device-card.is-online .device-ico { background:var(--accent-soft); color:var(--accent); }
.device-body { padding:0 var(--s-4) var(--s-4); display:flex; flex-direction:column; gap:var(--s-3); }
.qr-frame {
  width:min(260px,100%); aspect-ratio:1; margin:0 auto; display:grid; place-items:center;
  background:#fff; border:1px solid var(--border); border-radius:var(--r-lg); padding:10px;
}
.qr-frame img { width:100%; height:100%; object-fit:contain; image-rendering:pixelated; }
.pair-code { font-family:var(--mono); font-size:2rem; font-weight:700; letter-spacing:.14em; text-align:center; padding:var(--s-4); background:var(--surface-sunk); border-radius:var(--r-lg); border:1px dashed var(--border-strong); }
.countdown { text-align:center; font-size:.75rem; color:var(--text-3); }

/* --- reports --- */
/* --- report list --- */
/* One row per report. The columns collapse in a deliberate order as the
   viewport narrows: the excerpt goes first, then the counts, so the group
   name, the period and the status survive down to phone width. */
.report-row { gap:12px; padding:12px var(--s-4); color:inherit; }
.report-row:hover { text-decoration:none; }
.report-row .avatar { flex:none; }
/* basis 0, not auto: with flex-wrap on at phone width an "auto" basis makes
   the browser ask for the text's natural width and push the column onto its
   own line instead of letting it shrink and ellipsise. */
.report-row-main { flex:1 1 0; min-width:0; display:flex; flex-direction:column; gap:2px; }
.report-row-title { gap:8px; align-items:center; min-width:0; }
.report-row-title strong { font-size:.8125rem; }
.report-row-excerpt { max-width:60ch; }
.report-row-meta { flex:none; display:flex; gap:var(--s-4); align-items:center; white-space:nowrap; }
.report-row-meta b { color:var(--text); font-weight:650; }
.report-row-go { flex:none; display:inline-flex; color:var(--text-3); }
.report-row:hover .report-row-go { color:var(--text); }
.badge-xs { padding:0 6px; font-size:.625rem; line-height:1.4; }

@media (max-width:1023px) {
  .report-row-excerpt { display:none; }
}
@media (max-width:640px) {
  .report-row { flex-wrap:wrap; row-gap:6px; }
  .report-row-meta { gap:var(--s-3); order:3; flex:1 1 100%; }
  .report-row-go { display:none; }
}

.report-card { display:flex; flex-direction:column; gap:var(--s-3); padding:var(--s-4); transition:border-color var(--base) var(--ease), transform var(--base) var(--ease); }
.report-card:hover { border-color:var(--border-strong); }
.report-excerpt { font-size:.75rem; color:var(--text-2); line-height:1.6; }
.report-stats { display:flex; gap:var(--s-4); font-size:.75rem; color:var(--text-3); }
.report-stats b { color:var(--text); font-weight:650; }
.prose { font-size:.875rem; line-height:1.75; max-width:76ch; }
.prose p { margin-bottom:var(--s-3); }
.prose h4 { margin:var(--s-4) 0 var(--s-2); font-size:.9375rem; }
.prose ul { list-style:none; display:flex; flex-direction:column; gap:6px; margin-bottom:var(--s-3); }
.prose li { position:relative; padding-left:18px; }
.prose li::before { content:""; position:absolute; left:4px; top:9px; width:5px; height:5px; border-radius:50%; background:var(--accent); }
.prose strong { font-weight:650; color:var(--text); }

/* --- agents --- */
.agent-card { padding:var(--s-4); display:flex; flex-direction:column; gap:var(--s-3); }
.agent-meta { display:grid; grid-template-columns:repeat(2,1fr); gap:8px var(--s-3); font-size:.75rem; }
.agent-meta div { display:flex; justify-content:space-between; gap:8px; border-bottom:1px dashed var(--border-soft); padding-bottom:4px; }
.agent-meta span { color:var(--text-3); }
.prompt-preview { font-size:.75rem; color:var(--text-2); background:var(--surface-sunk); border-radius:var(--r-md); padding:10px; line-height:1.6; max-height:88px; overflow:hidden; position:relative; }
.counter { font-size:.6875rem; color:var(--text-3); text-align:right; }
.var-hints { display:flex; gap:5px; flex-wrap:wrap; }
.var-hints button { font-family:var(--mono); font-size:.6875rem; background:var(--surface-3); color:var(--accent-text); border-radius:var(--r-xs); padding:2px 7px; transition:background var(--base) var(--ease); }
.var-hints button:hover { background:var(--accent-soft); }

/* 6. RESPONSIVE / MOTION =================================================== */

.only-mobile { display:none; }
.only-desktop { display:inline-grid; }
/* Desktop: the sidebar can be tucked away. The class sits on <html> so the
   inline script in <head> can apply the remembered state before first paint. */
@media (min-width:1024px) {
  /* Slide with `left`, not transform: a transformed parent would trap the
     fixed-position toggle below, and that toggle has to stay on screen. */
  .sidebar { transition:left var(--slow) var(--ease), visibility 0s; }
  .shell { transition:margin-left var(--slow) var(--ease); }
  html.sidebar-collapsed .sidebar { left:calc(-1 * var(--sidebar-w)); visibility:hidden; transition:left var(--slow) var(--ease), visibility 0s var(--slow); }
  html.sidebar-collapsed .shell { margin-left:0; }
  /* the one toggle follows the sidebar out and parks at the screen edge */
  html.sidebar-collapsed .sidebar .sidebar-toggle {
    position:fixed; left:10px; top:calc((var(--topbar-h) - 34px) / 2); z-index:70; visibility:visible;
    background:var(--surface); border:1px solid var(--border); box-shadow:var(--shadow-1);
  }
  html.sidebar-collapsed .topbar { padding-left:56px; }
}
.only-light { display:block; }
.only-dark  { display:none; }
:root[data-theme="dark"] .only-light { display:none; }
:root[data-theme="dark"] .only-dark  { display:block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .only-light { display:none; }
  :root:not([data-theme="light"]) .only-dark  { display:block; }
}
:root[data-theme="light"] .only-light { display:block; }
:root[data-theme="light"] .only-dark  { display:none; }

@media (min-width:900px) {
  .auth { grid-template-columns:1fr 1fr; }
  .auth-aside { display:grid; place-items:center; padding:var(--s-6); border-left:1px solid var(--border); background:color-mix(in srgb,var(--surface) 55%,transparent); }
}

@media (max-width:1280px) {
  .grid-dash { grid-template-columns:minmax(0,1fr); }
  .inbox.show-info { grid-template-columns:300px minmax(0,1fr); }
  .inbox.show-info .pane-info { position:absolute; right:0; top:0; bottom:0; width:300px; z-index:20; box-shadow:var(--shadow-3); }
  .pane-conv { position:relative; }
}

@media (max-width:1023px) {
  .sidebar { transform:translateX(-100%); transition:transform var(--slow) var(--ease); box-shadow:none; }
  body.sidebar-open .sidebar { transform:none; box-shadow:var(--shadow-3); }
  .sidebar-foot .ws-state { display:flex; align-items:center; gap:7px; font-size:.6875rem; color:var(--text-2); }
  .shell { margin-left:0; }
  .only-mobile { display:inline-grid; }
  .only-desktop { display:none; }
  .topbar { padding:0 var(--s-3); }
  .topbar-title { font-size:.875rem; }
  .topbar-search { max-width:none; margin-left:0; }
  .main { padding:var(--s-4); }
  .user-meta { display:none; }
  .conn-text { display:none; }
  .conn { width:28px; padding:0; justify-content:center; }

  .inbox { grid-template-columns:minmax(0,1fr); }
  .inbox .pane-chats { display:flex; }
  .inbox .pane-conv { display:none; }
  .inbox.show-conv .pane-chats { display:none; }
  .inbox.show-conv .pane-conv { display:flex; }
  .inbox.show-info { grid-template-columns:minmax(0,1fr); }
  .inbox.show-info .pane-info { width:min(320px,88vw); }
  .conv-head { gap:8px; padding:var(--s-2); }
  .conv-title small { display:none; }
  .thread { padding:var(--s-3) var(--s-3) var(--s-2); }
  .msg { max-width:88%; }
  .composer { padding:var(--s-2) var(--s-3) calc(var(--s-2) + env(safe-area-inset-bottom)); }
  /* satu tombol lebih banyak (lampiran) di kotak yang sama: rapatkan kontrol
     supaya kolom teks tetap lebar di layar ponsel */
  .composer-box { gap:5px; padding:6px 6px 6px 10px; }
  .composer-box .btn-icon { width:30px; height:30px; }
  .composer-box .btn-icon .ico { width:16px; height:16px; }
  .media-img img { max-height:220px; }
  /* Keep the takeover warning: it is the one thing an operator must see
     before replying by hand. Just make it compact. */
  .composer-hint { margin-top:4px; gap:var(--s-2); }
  .composer-hint [data-composer-note] { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .scroll-bottom { bottom:84px; right:12px; }
}

@media (max-width:640px) {
  .topbar-search { display:none; }
  .topbar-title { flex:1; }
  .main { padding:var(--s-3); }
  .page-head { margin-bottom:var(--s-4); }
  .modal-root { padding:0; align-items:flex-end; }
  .modal-card { width:100%; max-height:92dvh; border-radius:var(--r-2xl) var(--r-2xl) 0 0; }
  .modal-body,.modal-head { padding-left:var(--s-4); padding-right:var(--s-4); }
  .modal-foot { padding-left:var(--s-4); padding-right:var(--s-4); }
  .modal-foot .btn { flex:1; }
  .toast-stack { right:var(--s-3); left:var(--s-3); bottom:var(--s-3); width:auto; }
  .msg { max-width:90%; }
  /* di layar sesempit ini label tombol kirim memakan lebar kolom teks;
     ikon pesawat kertas plus aria-label sudah cukup menjelaskan */
  .composer-box .btn-primary span { display:none; }
  .composer-box .btn-primary { padding:0 12px; }
  .grid-stats { grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--s-3); }
  .stat { padding:var(--s-3); }
  .stat-value { font-size:1.375rem; }
  .auth-card { padding:var(--s-5) var(--s-4); border:0; box-shadow:none; background:transparent; }
}

@media print {
  .sidebar,.topbar,.toast-stack,.no-print { display:none !important; }
  .shell { margin-left:0; }
  .main { padding:0; }
  .card { border:0; box-shadow:none; }
  body { background:#fff; color:#000; }
}

@media (prefers-reduced-motion: reduce) {
  *,*::before,*::after {
    animation-duration:.001ms !important; animation-iteration-count:1 !important;
    transition-duration:.001ms !important; scroll-behavior:auto !important;
  }
}

/* --- error page --- */
.error-page .empty { padding:var(--s-8) var(--s-4); }
.error-code {
  font-family:var(--mono); font-size:2.75rem; font-weight:700; letter-spacing:-.04em;
  color:var(--text-3); line-height:1; margin-bottom:var(--s-2);
}
.error-page .btn-group { margin-top:var(--s-4); }

/* --- dashboard --- */
.sk-chart { height:180px; border-radius:var(--r-lg); }
.dash-main { margin-top:var(--s-4); }
.activity-scroll { max-height:420px; overflow-y:auto; }
.dev-row { display:flex; align-items:center; gap:10px; padding:11px var(--s-4); border-bottom:1px solid var(--border-soft); }
.dev-row:last-child { border-bottom:0; }
.dev-row .grow strong { display:block; font-size:.8125rem; }
.dev-row .grow small { font-size:.6875rem; color:var(--text-3); font-family:var(--mono); }
.top-chat { display:flex; align-items:center; gap:10px; padding:7px 0; }
.top-chat + .top-chat { border-top:1px dashed var(--border-soft); }
.top-chat .bar { flex:1; min-width:60px; }

/* --- inbox extras --- */
.tick-failed { color:var(--danger); }
.pane-conv [data-back] .ico { transform:rotate(90deg); }
.chat-item[aria-current="true"] { background:var(--accent-soft); }
.pane-info .btn-group .btn { flex:1; }

/* --- devices --- */
.switch-row { align-items:flex-start; padding:7px 0; border-bottom:1px dashed var(--border-soft); }
.switch-row .switch-track { margin-top:2px; }
.switch-row .grow { display:flex; flex-direction:column; }
.sk-qr { width:100%; height:100%; border-radius:var(--r-md); }
.pair-grid { display:grid; grid-template-columns:minmax(0,260px) minmax(0,1fr); gap:var(--s-5); align-items:start; }
.pair-steps { counter-reset:step; display:flex; flex-direction:column; gap:7px; font-size:.8125rem; color:var(--text-2); }
.pair-steps li { counter-increment:step; display:flex; gap:9px; align-items:flex-start; }
.pair-steps li::before {
  content:counter(step); flex:none; width:19px; height:19px; border-radius:50%;
  background:var(--accent-soft); color:var(--accent-text);
  font-size:.6875rem; font-weight:700; display:grid; place-items:center;
}
.device-card .btn-group { margin-top:var(--s-1); }
@media (max-width:720px) { .pair-grid { grid-template-columns:minmax(0,1fr); } }

/* --- reports --- */
.load-more { display:flex; justify-content:center; margin-top:var(--s-5); }
.report-stat-grid { grid-template-columns:repeat(2,minmax(0,1fr)); }
.report-card-link { color:inherit; }
.report-card-link:hover { text-decoration:none; }

/* --- agents --- */
.prompt-input { min-height:200px; font-family:var(--mono); font-size:.75rem; line-height:1.7; }
.test-output {
  background:var(--surface-sunk); border:1px solid var(--border); border-radius:var(--r-md);
  padding:12px; font-size:.8125rem; line-height:1.65; white-space:pre-wrap; min-height:72px;
}
.test-output pre { margin-top:8px; padding:8px 10px; border-radius:var(--r-sm); background:var(--surface); border:1px solid var(--border-soft); white-space:pre-wrap; overflow-wrap:anywhere; max-height:320px; overflow-y:auto; }
.agent-card .avatar-lg { background:var(--violet-soft); color:var(--violet); border-radius:13px; }

/* --- rules --- */
.input-prio { width:76px; text-align:center; padding:5px 6px; min-height:28px; }
.cell-reply { max-width:320px; }
.tester { background:var(--surface-2); border:1px solid var(--border); border-radius:var(--r-lg); padding:var(--s-3); }
.tester-verdict { font-size:.75rem; font-weight:600; }
.tester-verdict.is-ok { color:var(--success); }
.tester-verdict.is-no { color:var(--text-3); }
.tester-verdict.is-warn { color:var(--warning); }

/* --- users --- */
.role-note { margin-top:var(--s-4); }
.role-list { display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:var(--s-3); margin-top:var(--s-3); }
.role-list > div { display:flex; gap:10px; align-items:flex-start; font-size:.8125rem; color:var(--text-2); }
.role-list dt { flex:none; }

/* --- settings --- */
.link-btn { color:var(--accent-text); font-size:.6875rem; text-decoration:underline; }
.curl-card { margin-top:var(--s-4); }
.theme-picker { display:flex; gap:var(--s-2); flex-wrap:wrap; }
.theme-opt { position:relative; }
.theme-opt input { position:absolute; opacity:0; width:0; height:0; }
.theme-opt span {
  display:inline-flex; align-items:center; gap:7px; padding:9px 14px;
  border:1px solid var(--border-strong); border-radius:var(--r-md);
  font-size:.8125rem; cursor:pointer; background:var(--surface);
  transition:all var(--base) var(--ease);
}
.theme-opt span .ico { width:16px; height:16px; color:var(--text-3); }
.theme-opt input:checked + span { border-color:var(--accent); background:var(--accent-soft); color:var(--accent-text); }
.theme-opt input:checked + span .ico { color:var(--accent); }
.theme-opt input:focus-visible + span { box-shadow:0 0 0 3px var(--accent-ring); }

/* --- profile --- */
.profile-grid { align-items:start; }

/* --- inbox: lokasi, teruskan, sunting --- */
/* Semua panel di sini disembunyikan lewat atribut `hidden`, jadi tidak ada
   satu pun aturan di bawah yang menyetel `display` pada elemen tersebut. */
.bubble-fwd { display:flex; align-items:center; gap:4px; margin-bottom:3px; font-size:.6875rem; font-style:italic; color:var(--text-3); }
.bubble-fwd .ico { width:13px; height:13px; }
.bubble-edited { font-style:italic; }

.loc-card { display:flex; flex-direction:column; gap:6px; min-width:min(216px,56vw); }
.loc-head { display:flex; align-items:flex-start; gap:8px; }
.loc-head > .ico { width:18px; height:18px; flex:none; margin-top:1px; color:var(--accent); }
.loc-head-text { display:flex; flex-direction:column; gap:1px; min-width:0; }
.loc-title { font-size:.8125rem; font-weight:650; overflow-wrap:anywhere; }
.loc-name,.loc-addr { font-size:.75rem; color:var(--text-2); overflow-wrap:anywhere; }
.loc-coords { font-family:var(--mono); font-size:.6875rem; color:var(--text-3); overflow-wrap:anywhere; }
.loc-link {
  display:inline-flex; align-items:center; gap:5px; align-self:flex-start;
  padding:4px 10px; border-radius:var(--r-pill); font-size:.75rem; font-weight:600;
  background:var(--surface); border:1px solid var(--border); color:var(--accent-text);
}
.loc-link:hover { background:var(--surface-3); text-decoration:none; }
.loc-link:focus-visible { box-shadow:0 0 0 3px var(--accent-ring); }
.loc-link .ico { width:13px; height:13px; }
.loc-preview { display:flex; align-items:center; gap:10px; flex-wrap:wrap; font-size:.75rem; color:var(--text-2); min-height:30px; }
.loc-preview .num { font-family:var(--mono); }

.msg { align-items:flex-end; gap:2px; }
.msg-actions { display:flex; align-items:center; flex:none; }
.msg.is-out .msg-actions { order:-1; }
.msg-menu-btn {
  width:26px; height:26px; border-radius:50%; display:grid; place-items:center;
  color:var(--text-3); opacity:0;
  transition:opacity var(--base) var(--ease), background var(--base) var(--ease), color var(--base) var(--ease);
}
.msg-menu-btn .ico { width:15px; height:15px; }
.msg:hover .msg-menu-btn,
.msg:focus-within .msg-menu-btn,
.msg-menu-btn[aria-expanded="true"] { opacity:1; }
.msg-menu-btn:hover { background:var(--surface-3); color:var(--text); }
.msg-menu-btn:focus-visible { opacity:1; box-shadow:0 0 0 3px var(--accent-ring); }
@media (hover:none) { .msg-menu-btn { opacity:.6; } }
.msg-menu { position:fixed; left:0; top:0; right:auto; min-width:186px; max-width:calc(100vw - 16px); }

.fwd-list {
  display:flex; flex-direction:column; gap:2px; padding:4px;
  max-height:min(42vh,320px); overflow-y:auto; overscroll-behavior:contain;
  border:1px solid var(--border); border-radius:var(--r-md); background:var(--surface-2);
}
.fwd-item { display:flex; align-items:center; gap:9px; padding:7px 8px; border-radius:var(--r-sm); cursor:pointer; }
.fwd-item:hover { background:var(--surface-3); }
.fwd-item input { appearance:none; width:16px; height:16px; flex:none; border:1.5px solid var(--border-strong); border-radius:5px; background:var(--surface); transition:all var(--base) var(--ease); }
.fwd-item input:checked { background:var(--accent); border-color:var(--accent); background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'><path d='m20 6-11 11-5-5'/></svg>"); background-size:11px; background-position:center; background-repeat:no-repeat; }
.fwd-item input:focus-visible { box-shadow:0 0 0 3px var(--accent-ring); }
.fwd-item .grow strong { display:block; font-size:.8125rem; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.fwd-item .grow small { display:block; font-size:.6875rem; color:var(--text-3); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.fwd-empty { padding:10px 8px; }

/* A tagged person inside a message. It reads as one word, not as a link: the
   dashboard cannot open somebody else's WhatsApp profile, so making it look
   clickable would promise something it cannot do. */
.mention {
  padding:0 3px; border-radius:4px; font-weight:600;
  background:color-mix(in srgb, var(--accent) 16%, transparent); color:var(--accent-text, var(--accent));
}
.msg.is-out .mention { background:color-mix(in srgb, #fff 24%, transparent); color:inherit; }

/* --- Jaring pengetahuan (halaman Knowledge) --- */
/* A force-laid graph of what the assistant knows: one node per entry, an edge
   where two entries share keywords. It is a picture of a body of knowledge
   rather than a measurement, so it is allowed to move — but only gently, and
   not at all for a reader who asked for less motion (see the media query at
   the end of this block). */
.knet {
  /* Tinggi ikut layar, bukan angka tetap. Kotak 380px cukup untuk 90 titik;
     sejak gambar memuat sampai 140, kotak itu memaksa semuanya berdesakan di
     satu bola dan garis kaitannya tidak kelihatan lagi. Batas bawah menjaga
     layar ponsel tetap masuk akal, batas atas menjaga kartu ini tidak
     menelan seluruh halaman di layar besar. */
  position:relative; width:100%; height:clamp(320px, 58vh, 580px); border-radius:var(--r-lg);
  background:
    radial-gradient(circle at 20% 15%, color-mix(in srgb, var(--accent) 14%, transparent), transparent 55%),
    radial-gradient(circle at 80% 85%, color-mix(in srgb, var(--violet, var(--accent)) 12%, transparent), transparent 55%),
    var(--surface-2);
  overflow:hidden;
}
.knet svg { display:block; width:100%; height:100%; }
/* A transparent backdrop behind the nodes: catches a drag on empty space to
   pan the view, while node drags (nodes are drawn on top) still move nodes. */
.knet-bg { cursor:grab; }
.knet-wrap.is-panning .knet-bg { cursor:grabbing; }
/* The graph controls overlay. It sits in a wrapper, not inside [data-net]:
   the svg host is emptied and rebuilt every animation frame, so a toolbar
   placed inside it would vanish on the next frame. */
.knet-wrap { position:relative; }
.knet-tools {
  position:absolute; top:var(--s-2); right:var(--s-2); z-index:2;
  display:flex; gap:4px; padding:3px; border-radius:var(--r-md);
  background:color-mix(in srgb, var(--surface) 72%, transparent);
  backdrop-filter:blur(4px);
}
.knet-tools .btn-icon { background:var(--surface-2); font-weight:600; }
/* Fullscreen is CSS, mirroring the agent room: the element stays in the
   document, so modals, toasts, and keyboard focus keep working. Escape or the
   button exits. */
.knet-wrap.is-full {
  position:fixed; inset:0; z-index:60; margin:0; padding:var(--s-3);
  background:var(--surface); display:flex; flex-direction:column;
}
.knet-wrap.is-full .knet { flex:1 1 auto; height:auto; border-radius:var(--r-md); }
/* Badge hitungan jaring boleh melipat. Isinya kalimat — "140 dari 312
   pengetahuan digambar · 194 kaitan" — bukan satu kata, dan white-space:nowrap
   bawaan .badge membuatnya mendorong seluruh halaman melebar di layar ponsel,
   yang muncul sebagai geseran mendatar di semua kartu, bukan hanya kartu ini. */
.knet-count { white-space:normal; text-align:right; }
.knet-edge { stroke:var(--border-strong); stroke-opacity:.45; pointer-events:none; }
/* Nodes are draggable, so the cursor says so and touch-action keeps a drag
   from being read as a page scroll. Only the node takes the gesture — the rest
   of the graph still scrolls normally on a phone. */
.knet-node { cursor:grab; touch-action:none; transition:filter var(--base) var(--ease); }
.knet-node:hover,.knet-node:focus-visible { filter:brightness(1.25); outline:none; }
.knet-node.is-pick { stroke:var(--text); stroke-width:2; }
.knet-node.is-drag { cursor:grabbing; filter:brightness(1.3); }
/* Parked by hand: a thin ring, so an arranged node is distinguishable from one
   the simulation is still moving. Double-click releases it. */
.knet-node.is-pinned circle:not(.knet-halo) { stroke:var(--text-3); stroke-width:1.5; }
/* The halo is what makes a busy entry read as "this keeps coming up". */
.knet-halo { opacity:.18; }
.knet-label { font-size:9px; fill:var(--text-2); pointer-events:none; }
.knet-empty {
  position:absolute; inset:0; display:grid; place-items:center; text-align:center;
  padding:var(--s-4); color:var(--text-3); font-size:.8125rem;
}
.knet-legend { display:flex; flex-wrap:wrap; gap:var(--s-3); margin-top:var(--s-2); font-size:.75rem; color:var(--text-2); }
.knet-legend span { display:inline-flex; align-items:center; gap:6px; }
.knet-legend i { width:9px; height:9px; border-radius:50%; display:inline-block; }
.knet-focus {
  margin-top:var(--s-2); padding:var(--s-3); border-radius:var(--r-lg);
  background:var(--surface-2); border:1px solid var(--border);
}
.knet-focus h4 { font-size:.875rem; margin:0 0 4px; }
.knet-focus p { font-size:.8125rem; color:var(--text-2); margin:0; }
@media (prefers-reduced-motion:reduce) {
  /* The layout still runs, it just stops drifting once it has settled; the
     picture is the point, the motion is decoration. */
  .knet-node,.knet-edge { transition:none; }
}

/* --- sasaran ketuk di peranti sentuh ---
   Tinggi 28–32px nyaman untuk kursor tetikus dan terlalu kecil untuk jari:
   ambang yang dipakai panduan antarmuka sentuh adalah 44px. Dibatasi ke
   peranti yang memang disentuh, bukan ke lebar layar, supaya jendela desktop
   yang dikecilkan tetap serapat sekarang.

   Ditaruh di akhir berkas dengan sengaja: .chip dan .cbx-opt didefinisikan
   jauh di atas, dan aturan dengan kekhususan sama yang datang lebih dulu
   akan kalah. */
@media (hover:none) and (pointer:coarse) {
  .filterbar { gap:10px; padding:12px var(--s-4); }
  .filterbar .input, .filterbar .select, .filterbar .btn { min-height:44px; }
  /* Combobox dinaikkan di mana pun ia berada, bukan hanya di dalam .filterbar.
     Filter perangkat di Kotak Masuk duduk langsung di panel daftar chat, dan
     aturan yang terikat .filterbar tidak menyentuhnya sama sekali. Tombol ini
     selalu sasaran ketuk, apa pun induknya. */
  .cbx-trigger { min-height:44px; }
  .filterbar .btn { padding-top:10px; padding-bottom:10px; }
  .filterbar .fb-sep { display:none; }
  .chips { gap:8px; }
  .chip { padding:11px 16px; font-size:.8125rem; }
  /* Daftar pilihan combobox juga ditekan dengan jari. */
  .cbx-opt { min-height:44px; }
  .cbx-input { min-height:44px; }
}

/* --- panggung agen (3D) -----------------------------------------------
   Tiga dimensi di sini dibangun dari transform CSS, bukan WebGL dan bukan
   pustaka 3D. Alasannya bukan selera: seluruh frontend aplikasi ini ditulis
   tanpa satu pun dependensi, asetnya ditanam ke dalam biner, dan menambah
   pustaka 3D berarti menambah ratusan kilobita ke setiap deploy demi satu
   kartu. Perspektif, kedalaman, urutan tumpuk, dan rotasi semuanya sudah
   ada di CSS; yang dihitung JavaScript hanya posisi dan sudut.

   Kedalaman diurus browser lewat preserve-3d, jadi tidak ada penyortiran
   z manual yang bisa salah. */
.astage {
  position:relative; height:520px; border-radius:var(--r-xl);
  border:1px solid var(--border); overflow:hidden;
  background:
    radial-gradient(120% 90% at 50% 0%, var(--surface-2) 0%, var(--surface) 55%, var(--surface-3) 100%);
  perspective:1500px; perspective-origin:50% 44%;
  cursor:grab; touch-action:none; user-select:none;
}
.astage:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
.astage.is-drag { cursor:grabbing; }
.astage.is-full {
  position:fixed; inset:0; z-index:60; height:100vh; width:100vw;
  border-radius:0; border:0;
}

/* Panel obrolan 2D di tengah-bawah: ruang LAYAR, bukan dunia 3D, jadi tidak
   pernah ikut berputar/terbalik. pointer-events:none supaya tidak menghalangi
   seret/zoom ruangannya. */
.astage-feed {
  position:absolute; left:50%; bottom:12px; transform:translateX(-50%);
  z-index:4; width:min(360px, 82%); max-height:148px; overflow:hidden;
  display:flex; flex-direction:column; gap:2px;
  padding:7px 10px 8px; border-radius:var(--r-lg);
  background:var(--surface); border:1px solid var(--border);
  box-shadow:0 8px 24px rgb(0 0 0 / .22);
  font-size:.6875rem; line-height:1.32; color:var(--text-2);
  pointer-events:none;
}
.astage-feed-head {
  font-size:.5625rem; font-weight:700; text-transform:uppercase; letter-spacing:.05em;
  color:var(--text-3); margin-bottom:1px;
}
.astage-feed-line { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.astage-feed-nama { font-weight:650; color:var(--text); }
.astage-feed-teks { color:var(--text-2); }
.astage-feed-line.is-sup .astage-feed-nama,
.astage-feed-line.is-sup .astage-feed-teks { color:var(--warning-text); }
.astage.is-full .astage-feed { width:min(460px, 60%); max-height:230px; bottom:26px; }

/* Supervisor: meja/papan nama beda warna supaya terbaca sebagai pengawas. */
.odesk.is-supervisor .oname { border-color:var(--warning); box-shadow:0 0 0 2px var(--warning-soft); }
.odesk.is-supervisor .oscreen-glass {
  background:linear-gradient(160deg, var(--warning) 0%, var(--warning-text) 100%);
}
.astage-world {
  position:absolute; inset:0; transform-style:preserve-3d;
  /* Transform diisi JavaScript tiap frame; transisi di sini hanya untuk
     perubahan yang bukan dari seretan, misal tombol pas-layar. */
  will-change:transform;
}

/* --- bangun kotak dari enam sisi -------------------------------------
   Seluruh perabot ruangan disusun dari satu bentuk: kotak. Ukurannya datang
   dari tiga variabel, jadi satu aturan ini cukup untuk meja, kursi, monitor,
   maupun badan orang, dan tidak ada ukuran yang ditulis dua kali.

   Tiap sisi diberi lapisan gelap atau terang yang berbeda supaya bentuknya
   terbaca tanpa cahaya sungguhan: tanpa itu kotak terlihat seperti satu
   tempelan datar berwarna rata. */
.ob { position:absolute; transform-style:preserve-3d; width:var(--w); height:var(--h); }
.ob > i {
  position:absolute; left:0; top:0; display:block; width:100%; height:100%;
  background:var(--c); border-radius:1px;
}
.ob > .f-fr { transform:translateZ(calc(var(--d) / 2)); }
.ob > .f-bk { transform:rotateY(180deg) translateZ(calc(var(--d) / 2)); filter:brightness(.72); }
.ob > .f-rt {
  width:var(--d); left:50%; margin-left:calc(var(--d) / -2);
  transform:rotateY(90deg) translateZ(calc(var(--w) / 2)); filter:brightness(.84);
}
.ob > .f-lf {
  width:var(--d); left:50%; margin-left:calc(var(--d) / -2);
  transform:rotateY(-90deg) translateZ(calc(var(--w) / 2)); filter:brightness(.84);
}
.ob > .f-tp {
  height:var(--d); top:50%; margin-top:calc(var(--d) / -2);
  transform:rotateX(90deg) translateZ(calc(var(--h) / 2)); filter:brightness(1.12);
}
.ob > .f-bt {
  height:var(--d); top:50%; margin-top:calc(var(--d) / -2);
  transform:rotateX(-90deg) translateZ(calc(var(--h) / 2)); filter:brightness(.6);
}

/* --- ruangan ---------------------------------------------------------
   Tanpa tembok dengan sengaja. Ruangan tertutup berarti kamera selalu
   menatap dinding dari sisi mana pun ia diputar, dan yang hendak dilihat di
   sini justru isinya. Batas ruangan ditandai lantai dan karpet, bukan
   tembok. */
.oroom { position:absolute; left:50%; top:50%; transform-style:preserve-3d; }
.og { position:absolute; left:0; top:0; transform-style:preserve-3d; }
.og-isi { position:absolute; left:0; top:0; transform-style:preserve-3d; }
.oplane { position:absolute; left:50%; top:50%; }
.ofloor {
  width:1500px; height:1200px; margin:-600px 0 0 -750px;
  transform:rotateX(90deg);
  background:
    repeating-linear-gradient(90deg, var(--border-soft) 0 1px, transparent 1px 125px),
    repeating-linear-gradient(0deg, var(--border-soft) 0 1px, transparent 1px 125px),
    var(--surface-2);
  box-shadow:0 0 120px 40px rgb(0 0 0 / .25) inset;
}
/* Karpet menandai area tamu tanpa perlu sekat. */
.okarpet {
  width:420px; height:300px; margin:-150px 0 0 125px;
  transform:rotateX(90deg) translateZ(1px);
  background:var(--surface-3); border-radius:16px; opacity:.8;
}
/* Kaca televisi dan papan tulis: dua permukaan yang memang memantul. */
.otv-kaca {
  position:absolute; inset:4px; border-radius:2px;
  background:linear-gradient(150deg, var(--info) 0%, var(--accent-text) 100%); opacity:.85;
}
.opapan > .f-fr { box-shadow:inset 0 0 24px rgb(0 0 0 / .12); }
.ogalon > i { opacity:.85; }

/* --- satu tempat kerja ------------------------------------------------ */
.odesk { position:absolute; left:0; top:0; transform-style:preserve-3d; cursor:pointer; }
.odesk-hit {
  /* Satu bidang tak terlihat yang menangkap klik untuk seluruh meja. Tanpa
     ini, klik harus tepat mengenai salah satu sisi kotak, dan sela antar
     kotak membuat meja terasa tidak bisa ditekan. */
  position:absolute; left:-90px; top:-250px; width:180px; height:260px;
  transform:translateZ(60px); background:transparent;
}
.odesk:hover .oscreen-glass, .odesk.is-pick .oscreen-glass { filter:brightness(1.35); }
.odesk.is-pick .oname { border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-ring); }

/* Layar monitor. Yang sedang bekerja berkedip pelan seperti ada yang
   mengetik di sana; yang nonaktif gelap. */
.oscreen-glass {
  position:absolute; left:0; top:0; width:100%; height:100%;
  background:linear-gradient(160deg, var(--accent) 0%, var(--accent-text) 100%);
  opacity:.9; transition:filter var(--base) var(--ease);
}
.odesk.is-busy .oscreen-glass,
.odesk.is-kerja .oscreen-glass { animation:owork 1.8s var(--ease) infinite; }
/* Sedang bertanya ke rekan: layarnya berubah warna, bukan sekadar berkedip,
   karena itu langkah yang melibatkan meja lain. */
.odesk.is-tanya .oscreen-glass {
  background:linear-gradient(160deg, var(--warning) 0%, var(--warning-text) 100%);
}
.odesk.is-off .oscreen-glass { background:var(--border-strong); opacity:.5; animation:none; }
@keyframes owork {
  0%,100% { filter:brightness(1); }
  45%     { filter:brightness(1.5); }
}
/* Baris-baris seperti log/kode yang bergulir di layar — hanya muncul dan
   bergerak saat agennya sedang bekerja; diam dan tak terlihat saat santai atau
   nonaktif. Digerakkan murni oleh kelas .is-kerja/.is-busy, tanpa JS. */
.oscreen-lines {
  position:absolute; left:7%; top:10%; width:86%; height:80%;
  opacity:0; transition:opacity var(--base) var(--ease);
  background:repeating-linear-gradient(0deg, rgb(255 255 255 / .55) 0 1px, transparent 1px 6px);
}
.odesk.is-busy .oscreen-lines,
.odesk.is-kerja .oscreen-lines { opacity:.65; animation:oscroll 1.1s linear infinite; }
.odesk.is-off .oscreen-lines { opacity:0; animation:none; }
@keyframes oscroll { from { background-position:0 0; } to { background-position:0 6px; } }

/* Papan nama: satu-satunya bagian yang dibalik menghadap kamera, karena ia
   tulisan. Perabotnya tidak dibalik — itu memang geometri. */
.oname {
  /* Digantung dari sisi BAWAHNYA supaya ia tumbuh ke atas dari titik
     gantungnya. Dengan top:0 papan ini tumbuh ke bawah dan menimpa kepala
     karyawannya. */
  position:absolute; left:50%; top:auto; bottom:0; width:150px; margin-left:-75px;
  padding:5px 8px; border-radius:var(--r-md);
  background:var(--surface); border:1px solid var(--border);
  box-shadow:0 6px 16px rgb(0 0 0 / .18); text-align:left;
}
.oname-top { display:flex; align-items:center; gap:6px; }
.oname-name {
  flex:1; min-width:0; font-size:.75rem; font-weight:650; color:var(--text);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.oname-sub {
  font-size:.625rem; color:var(--text-3); margin-top:1px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
/* Baris kerja: apa yang sedang dikerjakan agen detik ini. Dibedakan warnanya
   supaya mata langsung menemukan meja yang sedang sibuk di antara yang diam. */
.oname-kerja {
  margin-top:4px; padding:2px 6px; border-radius:var(--r-sm);
  background:var(--accent-soft); color:var(--accent-text);
  font-size:.625rem; font-weight:600;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.odesk.is-tanya .oname-kerja { background:var(--warning-soft); color:var(--warning-text); }
.oname-meta { display:flex; gap:7px; margin-top:4px; font-size:.625rem; color:var(--text-2); }
.oname-meta b { font-variant-numeric:tabular-nums; color:var(--text); font-weight:650; }

/* --- orang ------------------------------------------------------------
   Kaki benar-benar berengsel di pinggul, bukan kotak yang ditempel. Itu
   syarat supaya ia bisa berjalan: animasi memutar pangkal paha sementara
   posisi orangnya diatur JavaScript. Dua pembungkus per anggota badan karena
   keduanya memakai transform, dan satu elemen hanya punya satu. */
.oper { position:absolute; left:0; top:0; transform-style:preserve-3d; }
.oper-tubuh { position:absolute; left:0; top:-48px; transform-style:preserve-3d; }
.oanggota { position:absolute; left:0; top:0; transform-style:preserve-3d; }
.oayun { position:absolute; left:0; top:0; transform-style:preserve-3d; transform-origin:top center; }

/* Berjalan: paha dan lengan berayun berlawanan, seperti orang berjalan. */
.oper.is-jalan .okaki.is-kiri  > .oayun { animation:olangkahA .62s ease-in-out infinite; }
.oper.is-jalan .okaki.is-kanan > .oayun { animation:olangkahB .62s ease-in-out infinite; }
.oper.is-jalan .olengan.is-kiri  > .oayun { animation:olangkahB .62s ease-in-out infinite; }
.oper.is-jalan .olengan.is-kanan > .oayun { animation:olangkahA .62s ease-in-out infinite; }
.oper.is-jalan .oper-tubuh { animation:ogoyang .31s ease-in-out infinite; }
@keyframes olangkahA { 0%,100% { transform:rotateX(26deg); } 50% { transform:rotateX(-26deg); } }
@keyframes olangkahB { 0%,100% { transform:rotateX(-26deg); } 50% { transform:rotateX(26deg); } }
@keyframes ogoyang   { 0%,100% { margin-top:0; } 50% { margin-top:-3px; } }

/* Duduk: paha melipat ke arah meja (menjauh dari kamera) dan betis turun, jadi
   kakinya masuk ke bawah meja alih-alih menjulur ke depan ke arah penonton —
   itulah "posisi duduk terbalik" yang dulu terlihat. Lengan ikut condong ke
   arah meja supaya satu pose yang utuh. Tingginya nyaris sama dengan berdiri
   karena dudukan kursi memang setinggi pinggul. */
.oper.is-duduk .okaki > .oayun { transform:rotateX(78deg); }
.oper.is-duduk .olengan > .oayun { transform:rotateX(18deg); }

/* Gelembung di atas kepala: apa yang sedang ia kerjakan atau tanyakan. */
.obubble {
  position:absolute; left:50%; top:0; width:170px; margin-left:-85px;
  padding:6px 9px; border-radius:var(--r-md);
  background:var(--surface); border:1px solid var(--border);
  box-shadow:0 8px 20px rgb(0 0 0 / .25);
  font-size:.6875rem; font-weight:600; color:var(--text); text-align:center;
  white-space:normal; line-height:1.3; overflow:hidden;
}
/* Dua bagian: apa yang dikerjakan, lalu kutipan pesannya. Kutipan dibatasi
   dua baris, bukan satu baris terpotong di ujung, karena potongan di ujung
   membuang justru bagian yang paling berguna. */
.obubble-aksi { display:block; font-size:.625rem; color:var(--text-3); font-weight:600; }
.obubble-teks {
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  overflow:hidden; margin-top:2px; font-weight:500; color:var(--text);
}
/* Masuk dan keluar dibedakan arah warnanya, seperti gelembung chat. */
.obubble.is-masuk  { border-color:var(--info); }
.obubble.is-keluar { border-color:var(--accent); }
.obubble.is-hasil  { background:var(--success-soft); color:var(--success-text); border-color:var(--success); }
.obubble.is-hasil::after { border-top-color:var(--success-soft); }
.obubble::after {
  content:""; position:absolute; left:50%; bottom:-6px; margin-left:-6px;
  border:6px solid transparent; border-top-color:var(--surface); border-bottom:0;
}
.obubble.is-tanya { background:var(--warning-soft); color:var(--warning-text); border-color:var(--warning); }
.obubble.is-tanya::after { border-top-color:var(--warning-soft); }
/* Ngobrol santai antar-agen yang sedang menganggur: lebih kalem, hanya tepian
   info dan teks sedikit diredupkan. Latarnya tetap --surface, jadi ekor ::after
   bawaan sudah cocok. */
.obubble.is-ngobrol { border-color:var(--info); color:var(--text-2); }

/* Lampu status dipakai di papan nama, di daftar teks, dan di kepala panel
   obrolan, jadi aturannya berdiri sendiri. */
.astage-dot { width:9px; height:9px; border-radius:50%; flex:none; background:var(--text-3); }
.astage-dot.is-on { background:var(--success); }
.odesk.is-busy .astage-dot { background:var(--success); animation:astage-pulse 1.6s var(--ease) infinite; }
.odesk.is-idle .astage-dot { background:var(--info); }
.odesk.is-off { opacity:.62; }
.odesk.is-off .astage-dot { background:var(--border-strong); }
@keyframes astage-pulse {
  0%,100% { box-shadow:0 0 0 0 var(--success); }
  50%     { box-shadow:0 0 0 6px transparent; }
}

.astage-empty, .astage-hint { position:absolute; left:0; right:0; text-align:center; }
.astage-empty { top:50%; transform:translateY(-50%); padding:0 var(--s-4); color:var(--text-2); font-size:.8125rem; }
.astage-hint { bottom:8px; margin:0; font-size:.6875rem; color:var(--text-3); pointer-events:none; }

/* Panel obrolan, mengapung di dalam panggung supaya ikut terlihat saat
   panggungnya dibuka layar penuh. */
.astage-chat {
  position:absolute; right:10px; top:10px; bottom:10px; width:min(360px, calc(100% - 20px));
  display:flex; flex-direction:column; gap:8px;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  box-shadow:0 18px 40px rgb(0 0 0 / .22); padding:10px; z-index:2;
}
.astage-chat-head { display:flex; align-items:center; gap:8px; }
.astage-chat-head strong { font-size:.8125rem; }
.astage-chat-head small { color:var(--text-3); font-size:.6875rem; }
.astage-chat-log {
  flex:1; min-height:0; overflow:auto; display:flex; flex-direction:column; gap:6px;
  padding:4px; font-size:.8125rem;
}
.astage-msg { max-width:88%; padding:6px 9px; border-radius:var(--r-md); line-height:1.45; white-space:pre-wrap; overflow-wrap:anywhere; }
.astage-msg.is-me { align-self:flex-end; background:var(--accent); color:var(--accent-fg); }
.astage-msg.is-them { align-self:flex-start; background:var(--surface-3); color:var(--text); }
.astage-msg.is-err { align-self:stretch; background:var(--danger-soft); color:var(--danger-text); }
.astage-chat-form { display:flex; gap:6px; }
.astage-chat-form .input { flex:1; min-height:36px; }
.astage-note { font-size:.6875rem; color:var(--text-3); margin:0; }

/* Daftar teks di bawah panggung. Ini bukan hiasan: panggung 3D-nya
   aria-hidden, jadi daftar inilah yang dibaca pembaca layar dan yang tetap
   berguna kalau transform 3D tidak didukung. */
.astage-list { list-style:none; margin:var(--s-3) 0 0; padding:0; display:grid; gap:6px; }
.astage-list li {
  display:flex; align-items:center; gap:10px; padding:7px 10px;
  border:1px solid var(--border-soft); border-radius:var(--r-md); background:var(--surface-2);
  font-size:.8125rem;
}
.astage-list .astage-list-name { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.astage-list .astage-list-num { color:var(--text-2); font-size:.75rem; font-variant-numeric:tabular-nums; }

@media (max-width:640px) {
  .astage { height:380px; }
  .astage-chat { left:10px; width:auto; }
  /* Di lebar ponsel angka yang panjang mendesak nama agen sampai nol lebar,
     dan barisnya jadi hanya deretan angka tanpa pemiliknya. Namanya diberi
     barisnya sendiri. */
  .astage-list li { flex-wrap:wrap; }
  .astage-list .astage-list-name { flex:1 1 100%; }
  .astage-list .astage-list-num { flex:1 1 auto; }
}
/* Panggung yang berputar sendiri adalah gerakan dekoratif. Yang meminta
   gerakan dikurangi tetap mendapat panggungnya, hanya tidak berputar. */
@media (prefers-reduced-motion:reduce) {
  .odesk.is-busy .astage-dot,
  .odesk.is-busy .oscreen-glass,
  .odesk.is-kerja .oscreen-glass,
  .oper.is-jalan .okaki > .oayun,
  .oper.is-jalan .olengan > .oayun,
  .oper.is-jalan .oper-tubuh { animation:none; }
}
