/* ==================================================================
   Mair Capital — MIDNIGHT FINANCE
   Premium financial SaaS · modern trading intelligence
   Tenang, profesional, berpusat pada data. Dark mode adalah bawaan.

   SATU LAPIS TOKEN. Tidak ada hex yang berserak di seluruh aplikasi:
   setiap warna di berkas ini dan di seluruh view mengalir dari sini.

   Tiga tingkat, dan urutannya penting:
       primitive  -> nilai mentah, tidak pernah dipakai langsung di komponen
       semantic   -> peran ("permukaan", "positif"), inilah yang dipakai
       component  -> nilai khusus satu komponen, diturunkan dari semantic

   ATURAN WARNA SEMANTIK
       EMAS   kecerdasan / merek       -- BUKAN hijau
       HIJAU  positif, dan HANYA positif
       MERAH  negatif
       ORANYE peringatan               -- BUKAN amber: amber duduk terlalu
              dekat dengan emas merek, dan berdampingan keduanya terbaca
              sebagai satu warna
       BIRU   informasi

   Teks di atas emas berwarna NAVY, bukan putih. Putih di atas #C79A3E
   hanya 2,59:1; navy 6,39:1. Ini sering terlupa karena pada aksen ungu
   yang dipakai sebelum v0.9.2, putih justru benar.

   Warna semantik dipakai untuk BADGE, INDIKATOR, ANGKA PENTING, IKON, dan
   GARIS TIPIS. Latar tetap permukaan gelap netral. Tidak ada kartu yang
   seluruhnya hijau atau merah: 80% informasi netral, 20% sorotan.
   ================================================================== */

:root {
    /* ==================== 1. PRIMITIVE ====================
       Nilai mentah palet Midnight Finance. Jangan dipakai langsung di
       komponen -- selalu lewat token semantik di bawahnya. */

    --c-night-900: #0B1120;   /* background   */
    --c-night-800: #111827;   /* surface      */
    --c-night-700: #172033;   /* card         */
    --c-night-600: #1E293B;   /* card hover   */
    --c-night-500: #263247;   /* border       */
    --c-night-400: #334155;   /* border kuat  */

    /* AUDIT AKSESIBILITAS 31 Agustus 2026: #64748B hanya mencapai
       3,42:1 di atas kartu — di bawah WCAG AA 4,5:1 untuk teks normal,
       sedangkan token ini dipakai pada ~25 tempat berukuran 10-12px
       (kepala tabel, keterangan, placeholder, keadaan kosong).
       #8593AB mencapai 4,71:1 pada latar terburuk dan tetap lebih redup
       daripada --text-muted, sehingga hierarkinya utuh. */
    --c-slate-500: #8593AB;   /* muted        */
    --c-slate-400: #94A3B8;   /* teks sekunder*/
    --c-slate-50:  #F8FAFC;   /* teks utama   */

    --c-gold-500: #C79A3E;    /* AKSEN MEREK  */
    --c-gold-400: #E2BC6A;
    --c-gold-300: #EFD9A6;
    --c-navy-800: #111E3A;    /* teks di atas emas */
    --c-navy-700: #1B2C52;

    --c-green-500: #22C55E;
    --c-green-400: #4ADE80;
    --c-red-500:   #EF4444;
    --c-red-400:   #F87171;
    --c-orange-500: #F97316;
    --c-orange-400: #FB923C;
    --c-sky-500:   #38BDF8;
    --c-sky-400:   #7DD3FC;

    /* Lapisan transparan untuk latar badge dan sorotan lembut.
       Dipakai supaya warna semantik tidak pernah menjadi blok pekat. */
    --a-brand-16:    rgba(199, 154, 62, .18);
    --a-brand-10:    rgba(199, 154, 62, .12);
    --a-brand-32:    rgba(199, 154, 62, .34);
    --a-brand-45:    rgba(199, 154, 62, .48);
    --a-positive-14: rgba(34, 197, 94, .14);
    --a-positive-32: rgba(34, 197, 94, .32);
    --a-negative-14: rgba(239, 68, 68, .14);
    --a-negative-32: rgba(239, 68, 68, .32);
    --a-warning-14:  rgba(249, 115, 22, .14);
    --a-warning-32:  rgba(249, 115, 22, .32);
    --a-info-14:     rgba(56, 189, 248, .14);
    --a-info-32:     rgba(56, 189, 248, .32);
    --a-muted-12:    rgba(100, 116, 139, .12);
    --a-black-60:    rgba(0, 0, 0, .60);
    --a-surface-70:  rgba(17, 24, 39, .88);
    --a-hairline:    rgba(38, 50, 71, .55);

    /* ==================== 2. SEMANTIC ====================
       Peran, bukan warna. Inilah yang dipakai komponen. */

    /* Nama sesuai spesifikasi Midnight Finance, tersedia verbatim supaya
       tidak ada tebak-tebakan saat membacanya kembali:
           background #0B1120   surface #111827   card #172033
       Nama internal di bawahnya adalah alias yang sudah dipakai kode:
       `--bg-elevated` ADALAH surface, `--surface` ADALAH card. */
    --color-background: var(--c-night-900);
    --color-surface: var(--c-night-800);
    --color-card: var(--c-night-700);
    --color-border: var(--c-night-500);

    --bg: var(--color-background);
    --bg-elevated: var(--color-surface);
    --surface: var(--color-card);
    --surface-hover: var(--c-night-600);
    --border: var(--color-border);
    --border-strong: var(--c-night-400);

    --text: var(--c-slate-50);
    --text-muted: var(--c-slate-400);
    --text-dim: var(--c-slate-500);

    /* MEREK = EMAS, diambil dari logo Mair Capital. Hijau tidak pernah
       menjadi warna merek: ia sudah punya arti lain, dan memakainya dua
       kali membuat "positif" kehilangan maknanya.

       Teks di atas emas berwarna NAVY, bukan putih. Putih di atas #C79A3E
       hanya mencapai rasio 2,5:1 — tidak terbaca. Navy mencapai 7:1. */
    --brand: var(--c-gold-500);
    --brand-hover: var(--c-gold-400);
    --brand-soft: var(--a-brand-16);
    --brand-fg: var(--c-navy-800);

    --positive: var(--c-green-500);
    --positive-text: var(--c-green-400);
    --positive-soft: var(--a-positive-14);

    --negative: var(--c-red-500);
    --negative-text: var(--c-red-400);
    --negative-soft: var(--a-negative-14);

    --warning: var(--c-orange-500);
    --warning-text: var(--c-orange-400);
    --warning-soft: var(--a-warning-14);

    --info: var(--c-sky-500);
    --info-text: var(--c-sky-400);
    --info-soft: var(--a-info-14);

    --muted-soft: var(--a-muted-12);

    /* Alias lama supaya komponen yang belum disentuh tetap sah.
       Keduanya kini menunjuk emas, bukan hijau. */
    --accent: var(--brand);
    --accent-hover: var(--brand-hover);
    --accent-fg: var(--brand-fg);
    --danger: var(--negative);
    --ring: var(--a-brand-45);

    /* ==================== 3. SINYAL ====================
       Pemetaan sinyal PRD-07 ke peran semantik. Satu tempat, sehingga
       mengubah arti sebuah sinyal tidak menuntut menyisir seluruh view. */

    --signal-accumulation: var(--positive);
    --signal-distribution: var(--negative);
    --signal-hold: var(--info);
    --signal-take-profit: var(--warning);
    --signal-loss-warning: var(--negative);
    --signal-neutral: var(--text-dim);
    --signal-insufficient: var(--text-dim);

    /* Flow score adalah KECERDASAN, bukan keuntungan. Karena itu emas,
       bukan hijau: skor tinggi tidak berarti untung. */
    --flow-score: var(--brand);

    /* ==================== 4. SPASI ====================
       Skala tetap. Tidak ada nilai acak di luar daftar ini. */

    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 20px;
    --space-6: 24px;
    --space-7: 32px;
    --space-8: 40px;
    --space-9: 56px;
    --space-10: 72px;

    /* ==================== 5. RADIUS ====================
       Skala bertingkat, bukan satu nilai untuk segalanya. Radius adalah
       salah satu cara sebuah antarmuka memberi tahu apa yang besar dan apa
       yang kecil; menyamakan semuanya di 12px membuat kartu sebesar layar
       dan lencana seukuran jari terasa dari bahan yang sama. */

    --radius-card: 14px;      /* wadah besar: kartu, panel, modal   */
    --radius-button: 10px;    /* kendali yang bisa ditekan          */
    --radius-input: 10px;     /* sepadan dengan tombol di sebelahnya*/
    --radius-badge: 999px;    /* lencana selalu pil                 */
    --radius-sm: 8px;         /* elemen kecil di dalam kartu        */
    --radius: 12px;           /* alias lama, dipertahankan          */
    --radius-lg: 18px;        /* wadah terbesar                     */

    /* ==================== 6. TIPOGRAFI ====================
       Inter untuk seluruh antarmuka. Angka keuangan memakai
       tabular-nums supaya digitnya berbaris lurus antar-baris tabel --
       tanpa itu, membandingkan dua angka menuntut membacanya, bukan
       melihatnya. */

    --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    --font-numeric: 'Inter', system-ui, -apple-system, sans-serif;
    --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

    --fs-page-title: 32px;
    --fs-section: 20px;
    --fs-card: 15px;
    --fs-body: 14px;
    --fs-secondary: 12.5px;

    /* Tinggi baris dinyatakan, tidak diwariskan begitu saja. Judul besar
       butuh baris yang rapat; teks yang dibaca berurutan butuh yang lapang.
       Satu nilai untuk keduanya selalu salah di salah satu tempat. */
    --lh-tight: 1.15;
    --lh-heading: 1.25;
    --lh-body: 1.6;

    /* Judul besar dirapatkan sedikit, label kecil direnggangkan. Keduanya
       melawan kecenderungan bawaan huruf: pada ukuran besar jarak antar
       huruf terlihat melebar, pada ukuran kecil terlihat menyempit. */
    --ls-title: -0.02em;
    --ls-heading: -0.01em;
    --ls-label: 0.06em;

    /* ==================== 7. ELEVASI ====================
       Batas dan elevasi halus. Tidak ada cahaya neon.

       Bayangan disusun DUA LAPIS: satu lapis rapat yang menempel di tepi
       benda, satu lapis lebar yang jatuh ke latar. Satu bayangan tunggal
       yang lebar membuat kartu tampak melayang tanpa tepi; dua lapis
       membuatnya tampak duduk di atas permukaan.

       Sorotan tipis di sisi atas kartu meniru cara cahaya jatuh pada
       permukaan gelap. Nilainya sangat rendah dan disengaja: begitu
       terlihat sebagai garis, ia berubah menjadi hiasan. */

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .24), 0 1px 1px rgba(0, 0, 0, .16);
    --shadow: 0 2px 4px rgba(0, 0, 0, .20), 0 8px 24px rgba(0, 0, 0, .32);
    --shadow-lg: 0 4px 8px rgba(0, 0, 0, .24), 0 20px 48px rgba(0, 0, 0, .44);

    --highlight-top: inset 0 1px 0 rgba(255, 255, 255, .04);

    --sidebar-w: 248px;
    --header-h: 60px;
    --transition: 160ms cubic-bezier(.4, 0, .2, 1);
}

/* ------------------------------------------------------------------
   Dasar
   ------------------------------------------------------------------ */

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-sans);
    font-size: var(--fs-body);
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-feature-settings: 'cv11', 'ss01';
}

/* HIERARKI TIPOGRAFI
   Judul halaman 30/700 -> bagian 20/600 -> kartu 15/600 -> badan 14/400.
   Ukurannya tetap; bukan hasil menebak per halaman. */

.page-title {
    font-size: var(--fs-page-title);
    font-weight: 700;
    letter-spacing: var(--ls-title);
    line-height: var(--lh-tight);
    margin: 0 0 var(--space-2);
    text-wrap: balance;
}
.page-subtitle { font-size: var(--fs-secondary); color: var(--text-muted); margin: 0 0 var(--space-6); }
.section-title {
    font-size: var(--fs-section);
    font-weight: 600;
    letter-spacing: var(--ls-heading);
    line-height: var(--lh-heading);
    margin: var(--space-7) 0 var(--space-4);
}

/* Judul bagian pertama tidak butuh jarak di atasnya: yang di atasnya
   adalah tepi halaman, bukan bagian lain. */
.section-title:first-of-type { margin-top: 0; }

h3 { font-size: var(--fs-card); font-weight: 600; letter-spacing: -.1px; }

/* ANGKA KEUANGAN SELALU TABULAR.
   Tanpa ini, digit berlebar-beda membuat dua angka di baris berbeda tidak
   sejajar, dan membandingkannya menuntut MEMBACA, bukan MELIHAT. */
.num,
.cell-num,
.kpi-value,
.metric-value,
.table-app td.num,
.table-app th.num,
[data-numeric] {
    font-family: var(--font-numeric);
    font-variant-numeric: tabular-nums;
    font-feature-settings: 'tnum' 1, 'cv11' 1;
}

.cell-num, .table-app td.num, .table-app th.num { text-align: right; }

a { color: var(--accent); text-decoration: none; transition: color var(--transition); }
a:hover { color: var(--accent-hover); }

code, .mono, .font-mono { font-family: var(--font-mono); font-variant-ligatures: none; }

/* UKURAN BAWAAN IKON DI DALAM TEKS.
   icon() menghasilkan SVG tanpa lebar intrinsik. Di tempat yang punya aturan
   sendiri (tombol, lencana, nav) ukurannya sudah ditentukan; di paragraf dan
   daftar biasa, tanpa aturan ini SVG memuai memenuhi lebar induknya —
   sebuah centang setinggi 300px pernah muncul di kartu Akses API. */
p svg, li svg, dd svg, span:not([class]) svg, .field-hint svg, .usage-note svg,
.metric-sub svg, .disclaimer svg, .signal-disclaimer svg, .notif-empty svg {
    width: 14px;
    height: 14px;
    vertical-align: -2px;
    flex-shrink: 0;
}

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

button, [role="button"], .clickable { cursor: pointer; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 6px; border: 2px solid var(--bg); }
::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }

/* ------------------------------------------------------------------
   Kerangka layout
   ------------------------------------------------------------------ */

.app-shell { min-height: 100vh; }

.sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--sidebar-w);
    background: var(--bg-elevated);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    z-index: 1045;
    transition: transform var(--transition);
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    height: var(--header-h);
    padding: 0 var(--space-4);
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}

.brand-mark {
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    color: var(--text);
    flex-shrink: 0;
}

.brand-mark svg { display: block; }

.brand-text { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.brand-text strong { font-size: 14px; font-weight: 600; letter-spacing: .2px; }
.brand-text span { font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; }

.sidebar-nav { padding: var(--space-4) var(--space-3); overflow-y: auto; flex: 1; }

.nav-section {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 1.2px;
    color: var(--text-dim);
    padding: var(--space-2) var(--space-3) var(--space-1);
    font-weight: 600;
}

.nav-link-app {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 9px var(--space-3);
    border-radius: var(--radius-sm);
    color: var(--text-muted);
    font-weight: 500;
    font-size: 13.5px;
    margin-bottom: 2px;
    transition: background var(--transition), color var(--transition);
}

.nav-link-app:hover { background: var(--surface-hover); color: var(--text); }

.nav-link-app.active {
    background: linear-gradient(90deg, var(--a-brand-16), var(--a-brand-10));
    color: var(--text);
    box-shadow: inset 2px 0 0 var(--accent);
}

.nav-link-app svg { width: 17px; height: 17px; flex-shrink: 0; opacity: .85; }
.nav-link-app.active svg { color: var(--accent); opacity: 1; }

.sidebar-footer {
    padding: var(--space-3);
    border-top: 1px solid var(--border);
    font-size: 11px;
    color: var(--text-dim);
    flex-shrink: 0;
}

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

.topbar {
    position: sticky;
    top: 0;
    height: var(--header-h);
    background: var(--a-surface-70);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0 var(--space-5);
    z-index: 1020;
}

.topbar h1 { font-size: 16px; font-weight: 600; margin: 0; letter-spacing: -.2px; }
.topbar-meta { font-size: 11px; color: var(--text-dim); }

.page { padding: var(--space-5); flex: 1; }

.sidebar-toggle {
    display: none;
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-muted);
    border-radius: var(--radius-sm);
    width: 36px;
    height: 36px;
    place-items: center;
}

.sidebar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--a-black-60);
    z-index: 1040;
}

/* ------------------------------------------------------------------
   Kartu & KPI
   ------------------------------------------------------------------ */

.card-app {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);

    /* Bayangan rapat ditambah sorotan sangat tipis di sisi atas. Pada
       permukaan gelap, tepi yang sama sekali datar membuat kartu tampak
       seperti lubang, bukan seperti benda yang diletakkan di atas latar. */
    box-shadow: var(--shadow-sm), var(--highlight-top);
}

.card-app-header {
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.card-app-header h2 { font-size: var(--fs-card); font-weight: 600; margin: 0; letter-spacing: -.1px; }
.card-app-body { padding: var(--space-4); }

.kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: var(--space-4);
    margin-bottom: var(--space-5);
}

.kpi {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    padding: var(--space-4);
    position: relative;
    overflow: hidden;
    transition: border-color var(--transition), transform var(--transition);
}

.kpi:hover { border-color: var(--border-strong); transform: translateY(-1px); }

.kpi::after {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 2px;
    background: var(--kpi-accent, var(--border-strong));
    opacity: .9;
}

.kpi-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }

.kpi-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .9px;
    color: var(--text-dim);
    font-weight: 600;
}

.kpi-icon {
    width: 30px;
    height: 30px;
    border-radius: 8px;
    display: grid;
    place-items: center;
    background: var(--kpi-bg, var(--a-positive-14));
    color: var(--kpi-accent, var(--accent));
}

.kpi-icon svg { width: 16px; height: 16px; }

.kpi-value {
    font-family: var(--font-numeric);
    font-variant-numeric: tabular-nums;
    font-size: 28px;
    font-weight: 600;
    letter-spacing: -.5px;
    margin-top: var(--space-2);
    line-height: 1.1;
}

.kpi-sub { font-size: 11.5px; color: var(--text-dim); margin-top: var(--space-1); }
.kpi-sub .up { color: var(--positive-text); }
.kpi-sub .flat { color: var(--text-dim); }

/* Sparkline sederhana tanpa library eksternal. */
.sparkline { display: flex; align-items: flex-end; gap: 3px; height: 34px; margin-top: var(--space-3); }

.sparkline .bar {
    flex: 1;
    background: linear-gradient(180deg, var(--brand), var(--a-brand-16));
    border-radius: 2px 2px 0 0;
    min-height: 2px;
    transition: opacity var(--transition);
}

.sparkline .bar:hover { opacity: .7; }

/* ------------------------------------------------------------------
   Tabel
   ------------------------------------------------------------------ */

.table-wrap { overflow-x: auto; }

.table-app {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
    min-width: 620px;
}

.table-app thead th {
    background: var(--bg-elevated);
    color: var(--text-dim);
    font-size: 10.5px;
    text-transform: uppercase;
    letter-spacing: var(--ls-label);
    font-weight: 600;
    text-align: left;
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
    position: sticky;
    top: 0;
}

.table-app thead th a { color: inherit; display: inline-flex; align-items: center; gap: 4px; }
.table-app thead th a:hover { color: var(--text); }
.table-app thead th .sort-ind { color: var(--accent); font-size: 9px; }

.table-app tbody td {
    /* Baris tabel keuangan dibaca berjam-jam. Tambahan tiga piksel di
       atas dan di bawah tidak terlihat sebagai perubahan desain, tetapi
       terasa setelah baris kedua puluh. */
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--a-hairline);
    vertical-align: middle;
}

/* Baris terakhir tidak butuh garis: yang di bawahnya adalah tepi kartu. */
.table-app tbody tr:last-child td { border-bottom: 0; }

.table-app tbody tr { transition: background var(--transition); }
.table-app tbody tr:hover { background: var(--surface-hover); }
.table-app tbody tr:last-child td { border-bottom: 0; }

.cell-code {
    font-family: var(--font-numeric);
    font-weight: 600;
    letter-spacing: .3px;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.cell-muted { color: var(--text-muted); }
.cell-dim { color: var(--text-dim); font-size: 12px; }
.text-end-actions { text-align: right; white-space: nowrap; }

.empty-state { padding: var(--space-6) var(--space-4); text-align: center; color: var(--text-dim); }
.empty-state svg { width: 34px; height: 34px; opacity: .4; margin-bottom: var(--space-3); }
.empty-state p { margin: 0 0 var(--space-3); }

/* ------------------------------------------------------------------
   Badge
   ------------------------------------------------------------------ */

.badge-status {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: 11.5px;
    font-weight: 600;
    padding: 3px 10px;
    border-radius: var(--radius-badge);
    border: 1px solid transparent;
    letter-spacing: .2px;
    white-space: nowrap;
}

.badge-status::before {
    content: '';
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: currentColor;
}

/* Nama lama tetap sah dan kini menjadi ALIAS peran semantik yang sama.
   Menyisir puluhan view hanya untuk mengganti nama kelas akan mengubah
   banyak berkas tanpa mengubah satu piksel pun; yang penting adalah
   keduanya tidak boleh berbeda arti. */
.badge-ok     { background: var(--positive-soft); color: var(--positive-text); border-color: var(--a-positive-32); }
.badge-off    { background: var(--muted-soft);    color: var(--text-muted);    border-color: var(--border-strong); }
.badge-danger { background: var(--negative-soft); color: var(--negative-text); border-color: var(--a-negative-32); }
.badge-warn   { background: var(--warning-soft);  color: var(--warning-text);  border-color: var(--a-warning-32); }

/* Kode peran dan method HTTP TETAP monospace: keduanya benar-benar
   kode, dan lebar tetap per karakter memang gunanya di sana. */
.badge-role {
    font-family: var(--font-mono);
    font-size: 10.5px;
    padding: 2px 7px;
    border-radius: var(--radius-sm);
    background: var(--bg-elevated);
    color: var(--text-muted);
    border: 1px solid var(--border);
}

.badge-method {
    font-family: var(--font-mono);
    font-size: 10.5px;
    font-weight: 600;
    padding: 2px 6px;
    border-radius: 4px;
    background: var(--info-soft);
    color: var(--info-text);
}

.badge-http-2xx { color: var(--positive-text); }
.badge-http-4xx { color: var(--warning-text); }
.badge-http-5xx { color: var(--negative-text); }

/* ------------------------------------------------------------------
   Form & tombol
   ------------------------------------------------------------------ */

.form-label-app {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
    margin-bottom: 5px;
    display: block;
}

.form-label-app .req { color: var(--negative-text); }

.input-app,
.select-app {
    width: 100%;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    color: var(--text);
    border-radius: var(--radius-input);
    padding: 10px var(--space-3);
    font-size: 13.5px;
    font-family: inherit;
    transition: border-color var(--transition), box-shadow var(--transition);
}

.input-app::placeholder { color: var(--text-dim); }

.input-app:focus,
.select-app:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--ring);
}

.input-app.is-invalid,
.select-app.is-invalid { border-color: var(--danger); }

.input-mono { font-family: var(--font-mono); letter-spacing: .5px; text-transform: uppercase; }

.select-app {
    appearance: none;
    /* Panah digambar sebagai mask, bukan gambar berwarna: warnanya lalu
       datang dari token seperti elemen lain, dan ikut berubah saat fokus. */
    background-image: none;
    padding-right: var(--space-7);
    position: relative;
}

.select-wrap { position: relative; display: block; }

.select-wrap::after {
    content: '';
    position: absolute;
    right: var(--space-3);
    top: 50%;
    width: 10px;
    height: 10px;
    transform: translateY(-50%);
    pointer-events: none;
    background-color: var(--text-dim);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10z'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.field-hint { font-size: 11.5px; color: var(--text-dim); margin-top: 4px; }
.field-error { font-size: 11.5px; color: var(--negative-text); margin-top: 4px; display: flex; gap: 4px; align-items: center; }

.btn-app {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    border-radius: var(--radius-button);
    padding: 8px 14px;
    font-size: 13px;
    font-weight: 600;
    border: 1px solid transparent;
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition), color var(--transition), transform var(--transition);
    min-height: 38px;
    white-space: nowrap;
}

.btn-app:active { transform: translateY(1px); }
.btn-app svg { width: 15px; height: 15px; }

.btn-primary-app { background: var(--accent); color: var(--accent-fg); }
.btn-primary-app:hover { background: var(--accent-hover); color: var(--accent-fg); }

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

.btn-danger-app { background: transparent; border-color: var(--a-negative-32); color: var(--negative-text); }
.btn-danger-app:hover { background: var(--negative-soft); border-color: var(--negative-text); color: var(--negative-text); }

.btn-icon { padding: 6px; min-height: 32px; width: 32px; }
.btn-sm-app { padding: 5px 10px; font-size: 12px; min-height: 30px; }

/* ------------------------------------------------------------------
   Toolbar filter
   ------------------------------------------------------------------ */

.toolbar {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
    align-items: flex-end;
}

.toolbar .field { min-width: 150px; }
.toolbar .field-grow { flex: 1 1 220px; }

/* ------------------------------------------------------------------
   Paginasi
   ------------------------------------------------------------------ */

.pagination-app {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-top: 1px solid var(--border);
    flex-wrap: wrap;
}

.pagination-info { font-size: 12px; color: var(--text-dim); }
.pagination-list { display: flex; gap: 4px; list-style: none; margin: 0; padding: 0; }

.pagination-list a,
.pagination-list span {
    display: inline-grid;
    place-items: center;
    min-width: 32px;
    height: 32px;
    padding: 0 8px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-muted);
    font-size: 12.5px;
    font-family: var(--font-numeric);
    font-variant-numeric: tabular-nums;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}

.pagination-list a:hover { background: var(--surface-hover); color: var(--text); border-color: var(--border-strong); }
.pagination-list .current { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); font-weight: 600; }
.pagination-list .disabled { opacity: .35; }

/* ------------------------------------------------------------------
   Alert / flash
   ------------------------------------------------------------------ */

.alert-app {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--surface);
    font-size: 13px;
    margin-bottom: var(--space-4);
}

.alert-app svg { width: 17px; height: 17px; flex-shrink: 0; margin-top: 1px; }
.alert-success { border-color: var(--a-positive-32); background: var(--positive-soft); color: var(--positive-text); }
.alert-danger { border-color: var(--a-negative-32); background: var(--negative-soft); color: var(--negative-text); }
.alert-warning { border-color: var(--a-warning-32); background: var(--warning-soft); color: var(--warning-text); }
.alert-app .btn-close-app { margin-left: auto; background: none; border: 0; color: inherit; opacity: .6; padding: 0 4px; }
.alert-app .btn-close-app:hover { opacity: 1; }

/* ------------------------------------------------------------------
   Halaman login
   ------------------------------------------------------------------ */

.auth-shell {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: var(--space-5);
    /* Cahaya latar sangat tipis, emas merek. Sebelumnya hijau, yang
       membuat halaman masuk terbaca seperti kabar baik keuangan padahal
       ia belum menunjukkan angka apa pun. */
    background:
        radial-gradient(900px 420px at 15% -10%, var(--a-brand-10), transparent 62%),
        radial-gradient(700px 380px at 110% 110%, var(--a-brand-10), transparent 62%),
        var(--bg);
}

.auth-card {
    width: 100%;
    max-width: 380px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-6) var(--space-5);
    box-shadow: var(--shadow);
}

.auth-brand { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-5); }
.auth-card h1 { font-size: 19px; font-weight: 600; margin: 0 0 4px; }
.auth-card .subtitle { color: var(--text-dim); font-size: 13px; margin-bottom: var(--space-5); }
.auth-foot { text-align: center; margin-top: var(--space-5); font-size: 11.5px; color: var(--text-dim); }

.input-group-app { position: relative; }

.input-group-app .toggle-pass {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: 0;
    color: var(--text-dim);
    padding: 6px;
    display: grid;
    place-items: center;
    border-radius: var(--radius-sm);
    min-width: 30px;
    min-height: 30px;
}

.input-group-app .toggle-pass:hover { color: var(--text); }

/* ------------------------------------------------------------------
   Blok kunci rahasia (tampil satu kali)
   ------------------------------------------------------------------ */

.secret-box {
    background: var(--bg-elevated);
    border: 1px dashed var(--accent);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-3);
    flex-wrap: wrap;
}

.secret-box code {
    font-family: var(--font-mono);
    font-size: 12.5px;
    color: var(--positive-text);
    word-break: break-all;
    flex: 1 1 240px;
}

.copy-feedback { font-size: 11.5px; color: var(--positive-text); }

/* ------------------------------------------------------------------
   Halaman error
   ------------------------------------------------------------------ */

.error-shell { min-height: 100vh; display: grid; place-items: center; padding: var(--space-5); text-align: center; }
.error-code { font-family: var(--font-numeric); font-variant-numeric: tabular-nums; font-size: 64px; font-weight: 700; letter-spacing: -2px; color: var(--brand); line-height: 1; }
.error-message { color: var(--text-muted); margin: var(--space-3) 0 var(--space-5); max-width: 460px; }
.error-trace {
    text-align: left;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-dim);
    max-width: 800px;
    overflow-x: auto;
    white-space: pre-wrap;
}

/* ------------------------------------------------------------------
   Utilitas
   ------------------------------------------------------------------ */

.stack-2 { display: flex; flex-direction: column; gap: var(--space-2); }
.row-2 { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; }
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--space-4); }
.text-dim { color: var(--text-dim); }
.text-muted-app { color: var(--text-muted); }
/* Utilitas jarak mengikuti skala spasi; tidak ada nilai di luar daftar.
   `mt-2-app` dan `mt-3-app` sudah DIPAKAI di lima tempat sebelum rilis
   ini tetapi belum pernah didefinisikan, jadi jaraknya tidak pernah
   benar-benar muncul. */
.mb-2-app { margin-bottom: var(--space-2); }
.mb-3-app { margin-bottom: var(--space-3); }
.mb-4-app { margin-bottom: var(--space-4); }
.mb-5-app { margin-bottom: var(--space-5); }
.mt-2-app { margin-top: var(--space-2); }
.mt-3-app { margin-top: var(--space-3); }
.mt-4-app { margin-top: var(--space-4); }
.mt-5-app { margin-top: var(--space-5); }

/* Kolom peringkat broker: satu blok per kategori. */
.ranking-column { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.ranking-column h3 {
    font-size: 11px; font-weight: 600; letter-spacing: .8px;
    text-transform: uppercase; color: var(--text-dim); margin: 0;
}

/* Label kecil di atas sekelompok nilai. */
.codelabel {
    font-size: 10.5px; letter-spacing: 1px; text-transform: uppercase;
    color: var(--text-dim); margin: 0 0 var(--space-2); font-weight: 600;
}
.w-100-app { width: 100%; }

.info-list { display: grid; gap: var(--space-2); }
.info-row {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    padding: 7px 0;
    border-bottom: 1px solid var(--a-hairline);
    font-size: 13px;
}
.info-row:last-child { border-bottom: 0; }
.info-row dt { color: var(--text-dim); margin: 0; }
.info-row dd { margin: 0; font-family: var(--font-numeric); font-variant-numeric: tabular-nums; font-size: 12.5px; text-align: right; word-break: break-all; }

/* ------------------------------------------------------------------
   Responsif
   ------------------------------------------------------------------ */

@media (max-width: 991.98px) {
    .sidebar { transform: translateX(-100%); }
    .sidebar.open { transform: translateX(0); box-shadow: var(--shadow); }
    .sidebar-backdrop.show { display: block; }
    .main-wrap { margin-left: 0; }
    .sidebar-toggle { display: grid; }
}

@media (max-width: 575.98px) {
    :root { --header-h: 56px; }
    .page { padding: var(--space-4) var(--space-3); }
    .topbar { padding: 0 var(--space-3); }
    .kpi-value { font-size: 22px; }
    .kpi-grid { gap: var(--space-3); }
    .toolbar .field, .toolbar .field-grow { flex: 1 1 100%; min-width: 0; }
}

/* Perangkat sentuh: perbesar target agar memenuhi minimum 44x44px.
   Kepadatan tinggi tetap dipertahankan pada perangkat dengan mouse. */
@media (pointer: coarse) {
    .btn-app { min-height: 44px; }
    .btn-sm-app { min-height: 40px; }
    .btn-icon { width: 44px; min-height: 44px; padding: 10px; }
    .input-group-app .toggle-pass { min-width: 44px; min-height: 44px; }
    .nav-link-app { padding-top: 12px; padding-bottom: 12px; }
    .pagination-list a,
    .pagination-list span { min-width: 44px; height: 44px; }
    .input-app,
    .select-app { padding-top: 11px; padding-bottom: 11px; }
    .table-app tbody td { padding-top: 14px; padding-bottom: 14px; }
    .alert-app .btn-close-app { min-width: 44px; min-height: 44px; }
}

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

/* ==================================================================
   PRD-01.5 — Langganan, kuota, dan katalog paket
   Memakai token yang sama dengan PRD-01; tidak ada palet baru.
   ================================================================== */

.badge-info { background: var(--info-soft); color: var(--info-text); border-color: var(--a-info-32); }

/* ---------- Meteran kuota ---------- */

.quota { margin-top: var(--space-2); }

.quota-bar {
    height: 8px;
    border-radius: var(--radius-badge);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    overflow: hidden;
}

.quota-fill {
    display: block;
    height: 100%;
    /* Lebar awal nol: nilainya dipasang JavaScript dari data-fill, jadi
       tanpa ini bilahnya sempat tampil penuh sebelum diperbaiki. */
    width: 0;
    background: linear-gradient(90deg, var(--brand), var(--brand-hover));
    transition: width var(--transition);
}

.quota-fill.is-full { background: linear-gradient(90deg, var(--warning-text), var(--warning-text)); }
.quota-fill.is-over { background: linear-gradient(90deg, var(--negative), var(--negative-text)); }
.quota-fill.is-unlimited { background: linear-gradient(90deg, var(--border-strong), var(--text-dim)); opacity: .55; }

.quota-text {
    margin-top: 6px;
    font-size: 12px;
    color: var(--text-dim);
    font-family: var(--font-numeric);
    font-variant-numeric: tabular-nums;
}

.quota-text strong { color: var(--text); }
.quota-flag { color: var(--negative-text); font-weight: 600; }

/* ---------- Kartu paket ---------- */

.pricing-head { max-width: 620px; margin-bottom: var(--space-5); }
.pricing-head h2 { font-size: 22px; margin: 0 0 var(--space-2); letter-spacing: -.3px; }
.pricing-head p { color: var(--text-muted); margin: 0; font-size: 14px; }

.plan-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(258px, 1fr));
    gap: var(--space-4);
    align-items: start;
}

.plan-card {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--space-5) var(--space-4) var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    transition: border-color var(--transition), transform var(--transition);
}

.plan-card:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.plan-card.is-featured { border-color: var(--accent); box-shadow: 0 0 0 1px var(--a-positive-14); }
.plan-card.is-current { border-color: var(--info-text); }

.plan-ribbon {
    position: absolute;
    top: -9px;
    left: var(--space-4);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .5px;
    text-transform: uppercase;
    padding: 3px 9px;
    border-radius: 20px;
    background: var(--accent);
    color: var(--accent-fg);
}

.plan-ribbon.is-current { background: var(--info-text); color: var(--bg); }

.plan-card h3 { font-size: 17px; font-weight: 600; margin: 0; }
.plan-desc { color: var(--text-dim); font-size: 12.5px; margin: 0; }

.plan-price {
    font-family: var(--font-numeric);
    font-variant-numeric: tabular-nums;
    font-size: 28px;
    font-weight: 600;
    letter-spacing: -.6px;
    margin: var(--space-2) 0 0;
    line-height: 1.1;
}

.plan-price span { font-size: 12px; font-weight: 400; color: var(--text-dim); letter-spacing: 0; margin-left: 4px; }

.plan-features { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }

.plan-features li,
.feature-list li {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    font-size: 13px;
    color: var(--text-muted);
}

.plan-features li svg,
.feature-list li svg { width: 15px; height: 15px; flex-shrink: 0; margin-top: 2px; color: var(--accent); }
.plan-features li.is-off,
.feature-list li.is-off { color: var(--text-dim); }
.plan-features li.is-off svg,
.feature-list li.is-off svg { color: var(--border-strong); }
.plan-features li strong { color: var(--text); font-family: var(--font-numeric); font-variant-numeric: tabular-nums; font-size: 12.5px; margin-right: var(--space-1); }

.plan-cta-note {
    margin: auto 0 0;
    padding-top: var(--space-3);
    border-top: 1px solid var(--border);
    font-size: 12px;
    color: var(--text-dim);
}

.plan-headline { font-size: 20px; font-weight: 600; margin: 0; display: flex; flex-direction: column; gap: 2px; }
.plan-headline span { font-family: var(--font-sans); font-size: 13px; font-weight: 400; color: var(--text-dim); }

/* ---------- Daftar fitur di halaman langganan ---------- */

.feature-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.feature-list li em { margin-left: auto; font-style: normal; font-family: var(--font-numeric); font-variant-numeric: tabular-nums; font-size: 11.5px; color: var(--text-dim); }

/* ---------- Baris checkbox pada form admin ---------- */

.check-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 13px;
    color: var(--text-muted);
    cursor: pointer;
}

.check-row input[type="checkbox"] {
    width: 16px;
    height: 16px;
    accent-color: var(--accent);
    flex-shrink: 0;
    cursor: pointer;
}

.check-row span { display: flex; align-items: center; gap: 6px; }
.check-row em { font-style: normal; }

.feature-row {
    padding: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-elevated);
}

/* ---------- Kerangka halaman publik ---------- */

.public-shell {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background:
        radial-gradient(900px 420px at 12% -12%, var(--a-positive-14), transparent 60%),
        radial-gradient(760px 400px at 108% 108%, var(--info-soft), transparent 60%),
        var(--bg);
}

.public-bar {
    height: var(--header-h);
    border-bottom: 1px solid var(--border);
    background: var(--a-surface-70);
    backdrop-filter: blur(10px);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: 0 var(--space-5);
}

.public-brand { display: flex; align-items: center; gap: var(--space-3); color: inherit; }
.public-brand:hover { color: inherit; }

.public-main { flex: 1; width: 100%; max-width: 1120px; margin: 0 auto; padding: var(--space-6) var(--space-5); }

.public-foot {
    border-top: 1px solid var(--border);
    padding: var(--space-4) var(--space-5);
    text-align: center;
    font-size: 12px;
    color: var(--text-dim);
}

@media (max-width: 575.98px) {
    .public-bar { padding: 0 var(--space-3); }
    .public-main { padding: var(--space-4) var(--space-3); }
    .plan-grid { gap: var(--space-3); }
}

/* ==================================================================
   PRD-02 — Laporan sinkronisasi dan kartu provider
   ================================================================== */

.sync-report {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
    gap: var(--space-3);
}

.sync-report > div {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
}

.sync-report span {
    display: block;
    font-size: 10.5px;
    letter-spacing: .9px;
    text-transform: uppercase;
    color: var(--text-dim);
    font-weight: 600;
}

.sync-report strong {
    display: block;
    margin-top: 4px;
    font-family: var(--font-numeric);
    font-variant-numeric: tabular-nums;
    font-size: 20px;
    font-weight: 600;
    letter-spacing: -.3px;
}

.sync-report strong.is-good { color: var(--positive-text); }
.sync-report strong.is-bad  { color: var(--negative-text); }

.provider-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.provider-card.is-active { border-color: var(--a-positive-32); }
.provider-card.is-mock   { border-style: dashed; }

.provider-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); }
.provider-head h3 { font-size: 15px; font-weight: 600; margin: 0; }
.provider-head .provider-code { font-family: var(--font-numeric); font-size: 11.5px; letter-spacing: .3px; color: var(--text-dim); }

.capability-list { display: flex; flex-wrap: wrap; gap: 5px; }

.capability {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-family: var(--font-mono);
    font-size: 10.5px;
    padding: 3px 7px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-dim);
}

.capability.is-on { color: var(--positive-text); border-color: var(--a-positive-32); }
.capability.is-off { color: var(--text-dim); text-decoration: line-through; }

.license-note {
    font-size: 12px;
    color: var(--text-muted);
    background: var(--warning-soft);
    border: 1px solid var(--a-warning-32);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
    display: flex;
    gap: var(--space-2);
    align-items: flex-start;
}

.license-note svg { width: 15px; height: 15px; flex-shrink: 0; margin-top: 1px; color: var(--warning-text); }

.price-hero { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.price-hero .price-value { font-family: var(--font-numeric); font-variant-numeric: tabular-nums; font-size: 32px; font-weight: 700; letter-spacing: -1px; }
.price-hero .price-change { font-family: var(--font-numeric); font-variant-numeric: tabular-nums; font-size: 14px; font-weight: 600; }
.price-hero .price-change.is-up { color: var(--positive-text); }
.price-hero .price-change.is-down { color: var(--negative-text); }
.price-hero .price-change.is-flat { color: var(--text-dim); }

/* ------------------------------------------------------------
   Ikon di dalam petunjuk kecil.
   .field-hint sebelumnya tidak pernah menentukan ukuran svg, sehingga
   ikon inline di dalamnya memuai memenuhi lebar induknya. Baru terlihat
   pada halaman yang memakai ikon di petunjuk berbadan lebar.
   ------------------------------------------------------------ */
/* PROSA ADALAH PEMAKAIAN UTAMA, jadi bawaannya `block`.
   Sebelumnya `.field-hint` selalu `display: flex`, sehingga setiap
   <strong>, <code>, atau <em> di dalamnya menjadi ITEM FLEX tersendiri —
   kata-katanya terpecah menjadi kolom dan urutannya berantakan. Tujuh
   tempat sudah terdampak diam-diam, termasuk petunjuk kata sandi di
   Settings dan petunjuk kolom CSV di halaman portofolio.
   Varian berikon memakai `.with-icon`. */
.field-hint { display: block;}

.field-hint.with-icon { display: flex; align-items: flex-start; gap: 6px; }
.field-hint.with-icon svg { flex: none; margin-top: 2px; }
.field-hint svg { width: 13px; height: 13px; flex: 0 0 13px; margin-top: 1px; }

/* ============================================================
   PRD-03 — Analisis broker
   Angka uang dibaca dengan membandingkan digit per kolom, jadi
   perataannya kanan dan angkanya tabular supaya lebarnya tetap.
   ============================================================ */
.cell-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Lencana di dalam petak ringkasan mengikuti lebar isinya, bukan lebar
   petaknya, supaya tidak terbaca sebagai bilah penuh. */
.sync-report strong > .badge-status { display: inline-flex; font-size: 11px; }

/* Daftar endpoint: satu baris per endpoint, disalin utuh tanpa terpotong. */
.secret-box code { display: block; }
.secret-box br { display: none; }
th.cell-num { text-align: right; }

.ranking-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 18px;
}

.ranking-title {
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--text-dim);
    margin: 0 0 10px;
}

.ranking-list { list-style: none; margin: 0; padding: 0; counter-reset: rank; }

.ranking-list li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    padding: 6px 0;
    border-bottom: 1px solid var(--border);
    counter-increment: rank;
}

.ranking-list li:last-child { border-bottom: 0; }

.ranking-list li::before {
    content: counter(rank);
    font-size: 11px;
    color: var(--text-dim);
    min-width: 14px;
    font-variant-numeric: tabular-nums;
}

.rank-code { font-family: var(--font-numeric); font-weight: 600; letter-spacing: .3px; margin-right: auto; }
.rank-value { font-variant-numeric: tabular-nums; color: var(--text-dim); font-size: 13px; }

.alert-app p { margin: 4px 0 0; font-weight: 400; opacity: .9; }

/* Sentuhan pada layar sentuh mengikuti aturan PRD-01: minimal 44x44. */
@media (pointer: coarse) {
    .ranking-list li { padding: 10px 0; }
}

/* ============================================================
   PRD-04 — Intelijen pasar
   ============================================================ */

/* Bilah skor: angka tetap terbaca walau bilahnya sempit, jadi keduanya
   ditampilkan berdampingan, bukan angka di dalam bilah. */
/* Bilah skor lama DIHAPUS, bukan dibiarkan menganggur.
   Dulu ia berubah hijau di atas 60 dan merah di bawah 40 — mewarnai
   kecerdasan seperti keuntungan, dan menjanjikan hal yang tidak
   dikatakan angkanya. Penggantinya .flow-score berwarna emas merek. */

/* Kartu metrik arus: lebih padat dari .kpi, dipakai di dalam kartu. */
.flow-metrics {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
    gap: 12px;
}
.flow-metric {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-button);
    padding: var(--space-3) var(--space-4);
    min-width: 0;
}
.flow-metric .label {
    display: block; font-size: 10.5px; letter-spacing: .9px;
    text-transform: uppercase; color: var(--text-dim); font-weight: 600;
}
.flow-metric .value {
    display: block; margin-top: var(--space-2);
    font-family: var(--font-numeric); font-weight: 700;
    font-variant-numeric: tabular-nums;
    /* Nilai rupiah pasar bisa mencapai belasan digit. Ukurannya menyusut
       mengikuti lebar kolom alih-alih terpotong di tepi kartu -- angka
       yang terpotong lebih buruk daripada angka yang sedikit lebih kecil. */
    font-size: clamp(14px, 1.35vw + 6px, 18px);
    letter-spacing: -.3px;
    overflow-wrap: anywhere;
}
.flow-metric .sub { display: block; margin-top: 4px; font-size: 11px; color: var(--text-dim); }

/* Sparkline arus kumulatif. Digambar sebagai SVG inline; tanpa pustaka luar. */
.flow-chart { width: 100%; height: 108px; display: block; }
.flow-chart .axis { stroke: var(--border); stroke-width: 1; }
.flow-chart .line-pos { fill: none; stroke: var(--positive); stroke-width: 2; stroke-linejoin: round; }
.flow-chart .line-neg { fill: none; stroke: var(--negative); stroke-width: 2; stroke-linejoin: round; }
.flow-chart .dot { fill: var(--text-dim); }

.disclaimer {
    margin-top: 12px; padding: 10px 12px;
    border: 1px dashed var(--border); border-radius: var(--radius-sm);
    font-size: 11.5px; color: var(--text-dim);
}

@media (max-width: 640px) {
    .flow-score-track { width: 44px; }
    .flow-metrics { grid-template-columns: repeat(auto-fit, minmax(108px, 1fr)); }
}

/* Sentuhan pada layar sentuh mengikuti aturan PRD-01: minimal 44x44. */
@media (pointer: coarse) {
    .flow-metric { padding: 14px; }
}

/* ==================================================================
   MIDNIGHT FINANCE — PUSTAKA KOMPONEN
   Seluruhnya memakai lapis token di kepala berkas ini. Tidak ada satu
   pun nilai warna baru di bawah sini.

   80% INFORMASI NETRAL, 20% SOROTAN. Kartu tetap permukaan gelap;
   warna semantik hanya muncul pada badge, indikator, angka penting,
   ikon, dan garis tipis. Tidak ada kartu yang seluruhnya hijau atau
   merah -- blok warna pekat membuat mata lelah pada sesi panjang dan
   membuat seluruh halaman terbaca seperti peringatan.
   ================================================================== */

/* ------------------------------------------------------------------
   WARNA SEMANTIK SEBAGAI PERAN
   Satu set kelas dipakai lintas komponen supaya arti warna tidak
   pernah ditulis ulang per halaman.
   ------------------------------------------------------------------ */

.is-positive { color: var(--positive-text); }
.is-negative { color: var(--negative-text); }

/* Alias yang dipakai view sejak PRD-03. Sebelum rilis ini keduanya
   DIRUJUK di belasan berkas tetapi hanya didefinisikan untuk satu
   selektor sempit (.sync-report strong), sehingga hampir seluruh angka
   net dan P/L sebenarnya tampil tanpa warna sama sekali. Kini keduanya
   menunjuk peran semantik yang benar. */
.is-good { color: var(--positive-text); }
.is-bad  { color: var(--negative-text); }
td.is-good, td.is-bad, .cell-num.is-good, .cell-num.is-bad { font-variant-numeric: tabular-nums; }
.is-warning  { color: var(--warning-text); }
.is-info     { color: var(--info-text); }
.is-brand    { color: var(--brand); }
.is-muted    { color: var(--text-dim); }

/* P/L: hijau untung, merah rugi. Hanya ANGKANYA yang berwarna. */
.pl-positive { color: var(--positive-text); font-variant-numeric: tabular-nums; }
.pl-negative { color: var(--negative-text); font-variant-numeric: tabular-nums; }
.pl-flat     { color: var(--text-dim); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------------
   BADGE — varian semantik lengkap
   ------------------------------------------------------------------ */

.badge-brand    { background: var(--brand-soft);    color: var(--brand-hover);   border-color: var(--a-brand-32); }
.badge-positive { background: var(--positive-soft); color: var(--positive-text); border-color: var(--a-positive-32); }
.badge-negative { background: var(--negative-soft); color: var(--negative-text); border-color: var(--a-negative-32); }
.badge-warning  { background: var(--warning-soft);  color: var(--warning-text);  border-color: var(--a-warning-32); }
.badge-neutral  { background: var(--muted-soft);    color: var(--text-muted);    border-color: var(--border-strong); }

.badge-status svg { width: 12px; height: 12px; flex-shrink: 0; }

/* WARNA TIDAK PERNAH MENJADI SATU-SATUNYA PENANDA.
   Setiap badge membawa titik bentuk, ikon, atau teks -- sehingga
   pembaca dengan buta warna, layar monokrom, atau cetakan hitam-putih
   tetap dapat membedakannya. */
.badge-status.has-icon::before { display: none; }

/* ------------------------------------------------------------------
   METRIC CARD
   Satu angka penting dengan konteksnya. Latar netral; hanya nilai dan
   ikon yang boleh membawa warna semantik.
   ------------------------------------------------------------------ */

.metric-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    transition: border-color var(--transition);
}

.metric-card:hover { border-color: var(--border-strong); }

.metric-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}

.metric-label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .9px;
    text-transform: uppercase;
    color: var(--text-dim);
}

.metric-icon {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-button);
    display: grid;
    place-items: center;
    background: var(--brand-soft);
    color: var(--brand);
    flex-shrink: 0;
}

.metric-icon svg { width: 16px; height: 16px; }
.metric-icon.is-positive { background: var(--positive-soft); color: var(--positive-text); }
.metric-icon.is-negative { background: var(--negative-soft); color: var(--negative-text); }
.metric-icon.is-warning  { background: var(--warning-soft);  color: var(--warning-text); }
.metric-icon.is-info     { background: var(--info-soft);     color: var(--info-text); }

.metric-value {
    font-size: 28px;
    font-weight: 700;
    letter-spacing: -.8px;
    line-height: 1.1;
    color: var(--text);
}

.metric-sub {
    font-size: var(--fs-secondary);
    color: var(--text-muted);
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.metric-delta { display: inline-flex; align-items: center; gap: 3px; font-weight: 600; }
.metric-delta svg { width: 12px; height: 12px; }

.metric-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--space-4);
}

/* ------------------------------------------------------------------
   SIGNAL CARD
   Delapan hal yang WAJIB tampil pada setiap sinyal:
   signal, confidence, confidence band, reasons, data mode,
   data freshness, rule version, generated time.

   Kartunya tetap netral. Sinyal diberi warna hanya pada badge dan
   satu garis tipis di kiri -- cukup untuk dipindai, tidak sampai
   mengubah kartu menjadi blok merah atau hijau.
   ------------------------------------------------------------------ */

.signal-card {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 3px solid var(--signal-accent, var(--text-dim));
    border-radius: var(--radius-card);
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.signal-card.signal-accumulation      { --signal-accent: var(--signal-accumulation); }
.signal-card.signal-distribution      { --signal-accent: var(--signal-distribution); }
.signal-card.signal-hold              { --signal-accent: var(--signal-hold); }
.signal-card.signal-take-profit       { --signal-accent: var(--signal-take-profit); }
.signal-card.signal-loss-warning      { --signal-accent: var(--signal-loss-warning); }
.signal-card.signal-neutral           { --signal-accent: var(--signal-neutral); }
.signal-card.signal-insufficient-data { --signal-accent: var(--signal-insufficient); }

.signal-card-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.signal-headline { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }

.signal-name {
    font-size: var(--fs-section);
    font-weight: 600;
    letter-spacing: -.3px;
    color: var(--text);
}

/* CONFIDENCE ADALAH KEKUATAN BUKTI, BUKAN PELUANG.
   Ditulis "62 / 100" dengan pita di sebelahnya, tidak pernah "62%":
   tanda persen akan membacanya sebagai probabilitas. */
.confidence {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 132px;
}

.confidence-value {
    font-size: 22px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.5px;
    line-height: 1;
    color: var(--text);
}

.confidence-value small { font-size: 12px; font-weight: 500; color: var(--text-dim); letter-spacing: 0; }

.confidence-track {
    height: 4px;
    border-radius: var(--radius-badge);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    overflow: hidden;
}

/* Bilah confidence memakai UNGU MEREK, bukan hijau: kekuatan bukti
   adalah kecerdasan, bukan keuntungan. */
.confidence-fill { display: block; height: 100%; width: 0; background: var(--brand); transition: width var(--transition); }

.confidence-band {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .8px;
    text-transform: uppercase;
    color: var(--text-dim);
}

.signal-reasons { display: flex; flex-direction: column; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }

.signal-reasons li {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    font-size: var(--fs-body);
    color: var(--text-muted);
    line-height: 1.5;
}

.signal-reasons li::before {
    content: '';
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--signal-accent, var(--text-dim));
    margin-top: 8px;
    flex-shrink: 0;
}

/* Baris jejak: mode data, kesegaran, versi rule, waktu perhitungan.
   Keempatnya WAJIB terlihat -- tanpa mereka sebuah sinyal tidak dapat
   dipertanggungjawabkan. */
.signal-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--border);
    font-size: var(--fs-secondary);
}

.signal-meta-item { display: flex; flex-direction: column; gap: 2px; min-width: 92px; }
.signal-meta-item dt { color: var(--text-dim); font-size: 11px; letter-spacing: .5px; text-transform: uppercase; font-weight: 600; margin: 0; }
.signal-meta-item dd { color: var(--text-muted); margin: 0; font-variant-numeric: tabular-nums; }

.signal-disclaimer {
    font-size: 11.5px;
    color: var(--text-dim);
    line-height: 1.5;
    padding: var(--space-3);
    border: 1px dashed var(--border);
    border-radius: var(--radius-button);
    background: var(--bg-elevated);
}

/* ------------------------------------------------------------------
   DATA MODE — harus selalu terlihat
   Tiruan tidak boleh menyamar sebagai nyata, dan ringkasan tidak boleh
   menyamar sebagai data tingkat transaksi.
   ------------------------------------------------------------------ */

.mode-badge { font-weight: 600; letter-spacing: .4px; }
.mode-summary     { background: var(--info-soft);    color: var(--info-text);    border-color: var(--a-info-32); }
.mode-transaction { background: var(--brand-soft);   color: var(--brand-hover);  border-color: var(--a-brand-32); }
.mode-mock        { background: var(--warning-soft); color: var(--warning-text); border-color: var(--a-warning-32); }
/* Entri manual memakai nada netral, bukan merek. Ia bukan sumber istimewa;
   ia hanya sumber yang berbeda, dan pembaca perlu bisa membedakannya dari
   data provider tanpa membacanya sebagai lebih baik atau lebih buruk. */
.mode-manual      { background: var(--muted-soft);   color: var(--text);         border-color: var(--border-strong); }
.mode-unknown     { background: var(--muted-soft);   color: var(--text-muted);   border-color: var(--border-strong); }

.freshness-fresh       { background: var(--positive-soft); color: var(--positive-text); border-color: var(--a-positive-32); }
.freshness-stale       { background: var(--warning-soft);  color: var(--warning-text);  border-color: var(--a-warning-32); }
.freshness-unavailable { background: var(--muted-soft);    color: var(--text-muted);    border-color: var(--border-strong); }

/* ------------------------------------------------------------------
   FLOW SCORE — KECERDASAN, BUKAN KEUNTUNGAN
   Karena itu emas. Skor 90 tidak berarti untung 90; ia berarti bukti
   arusnya kuat. Mewarnainya hijau akan menjanjikan hal yang salah.
   ------------------------------------------------------------------ */

.flow-score { display: inline-flex; align-items: center; gap: var(--space-2); }

.flow-score-track {
    width: 64px;
    height: 6px;
    border-radius: var(--radius-badge);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    overflow: hidden;
    flex-shrink: 0;
}

.flow-score-fill { display: block; height: 100%; width: 0; background: var(--flow-score); transition: width var(--transition); }
.flow-score-value { font-variant-numeric: tabular-nums; font-weight: 600; min-width: 34px; text-align: right; color: var(--text); }

/* ------------------------------------------------------------------
   CHART CARD
   ------------------------------------------------------------------ */

.chart-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-card); }
.chart-card-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--space-3); padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--border); flex-wrap: wrap;
}
.chart-card-head h2 { font-size: var(--fs-card); font-weight: 600; margin: 0; }
.chart-card-body { padding: var(--space-5); }

.chart-legend { display: flex; gap: var(--space-4); flex-wrap: wrap; font-size: var(--fs-secondary); color: var(--text-muted); }
.chart-legend span { display: inline-flex; align-items: center; gap: var(--space-2); }
.chart-legend i { width: 12px; height: 2px; border-radius: 2px; background: var(--brand); display: inline-block; }
.chart-legend i.dashed { background: repeating-linear-gradient(90deg, var(--text-dim) 0 4px, transparent 4px 7px); }

/* ------------------------------------------------------------------
   USAGE CARD — kuota dan pemakaian paket
   ------------------------------------------------------------------ */

.usage-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.usage-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); }
.usage-title { font-size: var(--fs-card); font-weight: 600; margin: 0; }
.usage-count { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--text); }
.usage-count small { color: var(--text-dim); font-weight: 400; }

.usage-track { height: 8px; border-radius: var(--radius-badge); background: var(--bg-elevated); border: 1px solid var(--border); overflow: hidden; }
.usage-fill { display: block; height: 100%; width: 0; background: var(--brand); transition: width var(--transition); }
.usage-fill.is-near { background: var(--warning); }
.usage-fill.is-full { background: var(--negative); }
.usage-note { font-size: var(--fs-secondary); color: var(--text-dim); }

/* ------------------------------------------------------------------
   TABS
   ------------------------------------------------------------------ */

.tabs { display: flex; gap: var(--space-1); border-bottom: 1px solid var(--border); overflow-x: auto; }

.tab {
    appearance: none;
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    color: var(--text-muted);
    font-family: inherit;
    font-size: var(--fs-body);
    font-weight: 600;
    padding: var(--space-3) var(--space-4);
    white-space: nowrap;
    transition: color var(--transition), border-color var(--transition);
}

.tab:hover { color: var(--text); }
.tab[aria-selected="true"] { color: var(--text); border-bottom-color: var(--brand); }
.tab-panel { padding-top: var(--space-5); }
.tab-panel[hidden] { display: none; }

/* ------------------------------------------------------------------
   MODAL & DRAWER
   ------------------------------------------------------------------ */

.overlay {
    position: fixed;
    inset: 0;
    background: var(--a-black-60);
    backdrop-filter: blur(2px);
    z-index: 1050;
    display: none;
}

.overlay.open { display: block; }

.modal-app {
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: min(560px, calc(100vw - var(--space-8)));
    max-height: calc(100vh - var(--space-8));
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-lg);
    z-index: 1060;
    display: none;
}

.modal-app.open { display: block; }
.modal-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--border); }
.modal-head h2 { font-size: var(--fs-card); font-weight: 600; margin: 0; }
.modal-body { padding: var(--space-5); }
.modal-foot { display: flex; justify-content: flex-end; gap: var(--space-2); padding: var(--space-4) var(--space-5); border-top: 1px solid var(--border); }

.drawer {
    position: fixed;
    inset: 0 0 0 auto;
    width: min(420px, 100vw);
    background: var(--surface);
    border-left: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
    z-index: 1060;
    transform: translateX(100%);
    transition: transform var(--transition);
    display: flex;
    flex-direction: column;
}

.drawer.open { transform: translateX(0); }
.drawer-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--border); flex-shrink: 0; }
.drawer-body { padding: var(--space-5); overflow-y: auto; flex: 1; }

/* ------------------------------------------------------------------
   TOOLTIP
   ------------------------------------------------------------------ */

.tip { position: relative; display: inline-flex; align-items: center; gap: var(--space-1); border-bottom: 1px dotted var(--text-dim); cursor: help; }

/* TOOLTIP TIDAK MENEMPATI TATA LETAK SAAT TERSEMBUNYI.
   Sebelum V0.9.1 ia hanya ber-`opacity: 0`, sehingga kotaknya selebar
   260px tetap ikut dihitung dan MENDORONG lebar dokumen: halaman detail
   saham meluber mendatar di 1024px gara-gara satu tooltip confidence yang
   tidak terlihat. `display: none` menghilangkan kontribusinya sepenuhnya.

   Harganya: transisi memudar hilang. Tooltip yang muncul seketika jauh
   lebih baik daripada tooltip yang merusak tata letak halaman. */
.tip::after {
    display: none;
    content: attr(data-tip);
    position: absolute;
    bottom: calc(100% + var(--space-2));
    left: 50%;
    transform: translateX(-50%);
    width: max-content;
    max-width: min(260px, 80vw);
    background: var(--bg-elevated);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-button);
    box-shadow: var(--shadow);
    color: var(--text-muted);
    font-size: var(--fs-secondary);
    font-weight: 400;
    line-height: 1.45;
    padding: var(--space-2) var(--space-3);
    pointer-events: none;
    z-index: 1070;
    white-space: normal;
    text-align: left;
}

.tip:hover::after,
.tip:focus-visible::after { display: block; }

/* ------------------------------------------------------------------
   EMPTY / LOADING / ERROR STATE
   Ketiganya berbeda dan tidak boleh tertukar:
       kosong  -- belum ada isinya
       memuat  -- sedang diambil
       galat   -- ada yang salah
   Menampilkan "tidak ada data" saat sebenarnya gagal adalah berbohong
   kepada pembaca.
   ------------------------------------------------------------------ */

.state {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-3);
    padding: var(--space-8) var(--space-5);
    color: var(--text-muted);
}

.state-icon { width: 44px; height: 44px; border-radius: var(--radius-card); display: grid; place-items: center; background: var(--bg-elevated); border: 1px solid var(--border); color: var(--text-dim); }
.state-icon svg { width: 22px; height: 22px; }
.state h3 { margin: 0; font-size: var(--fs-card); font-weight: 600; color: var(--text); }
.state p { margin: 0; font-size: var(--fs-body); max-width: 46ch; line-height: 1.55; }

/* Ketiganya berbagi kerangka .state tetapi ikonnya berbeda nada,
   sehingga sekilas pun ketiganya tidak tertukar. */
.state-empty .state-icon   { background: var(--bg-elevated);    border-color: var(--border);         color: var(--text-dim); }
.state-error .state-icon   { background: var(--negative-soft);  border-color: var(--a-negative-32);  color: var(--negative-text); }
.state-loading .state-icon { background: var(--brand-soft);     border-color: var(--a-brand-32);     color: var(--brand); }

.spinner {
    width: 20px;
    height: 20px;
    border: 2px solid var(--border-strong);
    border-top-color: var(--brand);
    border-radius: 50%;
    animation: spin 720ms linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* Rangka pemuatan: bentuk halaman terlihat lebih dulu, sehingga tata
   letaknya tidak melompat saat isinya tiba. */
.skeleton {
    background: linear-gradient(90deg, var(--bg-elevated) 0%, var(--surface-hover) 50%, var(--bg-elevated) 100%);
    background-size: 200% 100%;
    animation: shimmer 1.4s ease-in-out infinite;
    border-radius: var(--radius-button);
    height: 14px;
}

@keyframes shimmer { to { background-position: -200% 0; } }

/* ------------------------------------------------------------------
   GRID 12 KOLOM — desktop, adaptif di tablet, satu kolom di ponsel
   ------------------------------------------------------------------ */

/* PREFIKS `g-` BUKAN GAYA PENAMAAN, MELAINKAN KEHARUSAN.
   Bootstrap 5 dimuat di layout sejak PRD-01 dan sudah memiliki `.col-3`,
   `.col-4`, `.col-6`, dan seterusnya dengan arti yang sama sekali berbeda
   (`width: 33.33%` untuk sistem flex-nya). Memakai nama yang sama membuat
   lebar Bootstrap menang atas area grid kita: kartu selebar 365px menyusut
   menjadi 122px — 33,33% dari areanya sendiri. */

.grid-12 { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--space-5); }

.g-col-3  { grid-column: span 3; }
.g-col-4  { grid-column: span 4; }
.g-col-6  { grid-column: span 6; }
.g-col-8  { grid-column: span 8; }
.g-col-9  { grid-column: span 9; }
.g-col-12 { grid-column: span 12; }

@media (max-width: 1199.98px) {
    .g-col-3 { grid-column: span 6; }
    .g-col-4 { grid-column: span 6; }
    .g-col-8, .g-col-9 { grid-column: span 12; }
}

@media (max-width: 767.98px) {
    .grid-12 { gap: var(--space-4); }
    .g-col-3, .g-col-4, .g-col-6, .g-col-8, .g-col-9 { grid-column: span 12; }
}

/* ------------------------------------------------------------------
   PONSEL — informasi kritis saja
   Yang wajib terlihat tanpa menggeser: ticker, harga, sinyal,
   confidence, net flow, P/L. Kolom bertanda .col-optional disembunyikan
   supaya keenamnya muat, dan sisanya tetap dapat dicapai dengan
   menggeser tabel secara mendatar.
   ------------------------------------------------------------------ */

@media (max-width: 767.98px) {
    .table-app .col-optional { display: none; }
    .signal-card { padding: var(--space-4); }
    .signal-meta { gap: var(--space-3) var(--space-4); }
    .confidence { min-width: 100%; }
    .metric-value { font-size: 24px; }
    .page-title { font-size: 24px; }
    .section-title { font-size: 18px; }
}

/* Tabel selalu dapat digeser mendatar, tidak pernah terpotong. */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* ------------------------------------------------------------------
   AKSESIBILITAS
   WARNA TIDAK PERNAH MENJADI SATU-SATUNYA PENANDA STATUS. Setiap
   penanda membawa ikon atau teks di samping warnanya.
   ------------------------------------------------------------------ */

.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.skip-link {
    position: absolute;
    left: var(--space-3);
    top: -60px;
    z-index: 1080;
    background: var(--surface);
    border: 1px solid var(--brand);
    color: var(--text);
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-button);
    transition: top var(--transition);
}

.skip-link:focus { top: var(--space-3); }

@media (prefers-contrast: more) {
    :root { --border: var(--c-night-400); --text-muted: var(--c-slate-50); }
}

/* ------------------------------------------------------------------
   NADA KPI SEBAGAI KELAS, BUKAN STYLE SEBARIS

   Sebelum rilis ini, dua puluh satu kartu KPI menyetel warnanya lewat
   `style="--kpi-accent: var(--green-500); --kpi-bg: rgba(34,197,94,.12)"`.
   Itu melanggar aturan lapis token dalam dua cara sekaligus: nilai rgba
   ditulis mentah di dalam view, dan nama primitif dirujuk langsung dari
   markup. Ketika primitif diganti pada rilis ini, seluruh dua puluh satu
   kartu itu diam-diam kehilangan aksennya — persis kegagalan yang
   dicegah oleh melarang hex berserak.

   Kini nada dipilih dengan KELAS. Satu tempat, dan tidak mungkin
   menunjuk warna yang sudah tidak ada.
   ------------------------------------------------------------------ */

.kpi.tone-brand,    .metric-card.tone-brand    { --kpi-accent: var(--brand);    --kpi-bg: var(--brand-soft); }
.kpi.tone-positive, .metric-card.tone-positive { --kpi-accent: var(--positive); --kpi-bg: var(--positive-soft); }
.kpi.tone-negative, .metric-card.tone-negative { --kpi-accent: var(--negative); --kpi-bg: var(--negative-soft); }
.kpi.tone-warning,  .metric-card.tone-warning  { --kpi-accent: var(--warning);  --kpi-bg: var(--warning-soft); }
.kpi.tone-info,     .metric-card.tone-info     { --kpi-accent: var(--info);     --kpi-bg: var(--info-soft); }
.kpi.tone-neutral,  .metric-card.tone-neutral  { --kpi-accent: var(--border-strong); --kpi-bg: var(--muted-soft); }

/* Cip avatar di topbar. Dulu warnanya ditulis sebaris di markup. */
.avatar-chip {
    width: 30px;
    height: 30px;
    border-radius: var(--radius-button);
    display: grid;
    place-items: center;
    background: var(--brand-soft);
    color: var(--brand);
    flex-shrink: 0;
}

.avatar-chip svg { width: 16px; height: 16px; }

/* Baris tabel yang memuat daftar alasan menjadi tinggi. Isi sel lain
   dirata-atas supaya tidak melayang di tengah ruang kosong. */
.table-app tr.row-top td { vertical-align: top; padding-top: var(--space-3); }
.table-app td.cell-reasons { min-width: 260px; }

.signal-reasons.is-compact { gap: var(--space-1); }
.signal-reasons.is-compact li { font-size: var(--fs-secondary); line-height: 1.45; }
.signal-reasons.is-compact li::before { margin-top: 7px; }

/* ------------------------------------------------------------------
   DEFINITION GRID
   Pasangan label/nilai untuk ringkasan. Dipakai halaman Signal Engine
   dan kinerja portofolio.

   Sebelum rilis ini `.summary-grid` dan `.list-plain` DIRUJUK di view
   tetapi tidak pernah didefinisikan, sehingga label dan nilainya
   menempel tanpa jarak ("ArahPOSITIVE"). Ini definisinya.
   ------------------------------------------------------------------ */

.summary-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--space-4);
}

.summary-grid > div {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-3);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-button);
    min-width: 0;
}

.summary-grid .label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .8px;
    text-transform: uppercase;
    color: var(--text-dim);
}

.summary-grid .value {
    font-size: var(--fs-body);
    font-weight: 600;
    color: var(--text);
    font-variant-numeric: tabular-nums;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    min-width: 0;
}

/* Daftar tanpa bullet bawaan browser; butir diberi titik sendiri. */
.list-plain { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.list-plain li { display: flex; align-items: flex-start; gap: var(--space-2); color: var(--text-muted); line-height: 1.5; }
.list-plain li::before {
    content: '';
    width: 4px; height: 4px;
    border-radius: 50%;
    background: var(--text-dim);
    margin-top: 8px;
    flex-shrink: 0;
}

/* Kotak rahasia bergaris penuh (bukan putus-putus) untuk konteks yang
   bukan peringatan. Dulu ditulis sebagai style sebaris di dua view. */
.secret-box.is-solid { border-style: solid; border-color: var(--border); }

/* ==================================================================
   PRD-08 — DASHBOARD INTELLIGENCE & USER EXPERIENCE
   Seluruhnya memakai lapis token Midnight Finance di kepala berkas ini.
   Tidak ada satu pun nilai warna baru di bawah sini.
   ================================================================== */

/* ------------------------------------------------------------------
   TOPBAR: pencarian global, status pasar, notifikasi
   ------------------------------------------------------------------ */

.topbar-title { min-width: 0; }
.topbar-title h1 { font-size: 16px; font-weight: 600; margin: 0; letter-spacing: -.2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.topbar-search { position: relative; flex: 1 1 320px; max-width: 420px; margin: 0 var(--space-4); }
.topbar-search .input-app { padding-left: var(--space-7); }

.topbar-search-icon {
    position: absolute;
    left: var(--space-3);
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-dim);
    pointer-events: none;
    display: grid;
    place-items: center;
}

.topbar-search-icon svg { width: 15px; height: 15px; }

.topbar-actions { display: flex; align-items: center; gap: var(--space-3); margin-left: auto; }
.topbar-user { gap: 0; line-height: 1.2; }
.topbar-user strong { font-size: 12.5px; }
.topbar-user span { font-size: 11px; }

.notif { position: relative; }

/* Titik pemberitahuan membawa juga teks tersembunyi bagi pembaca layar:
   sebuah titik berwarna tanpa keterangan tidak memberi tahu apa pun. */
.notif-dot {
    position: absolute;
    top: 6px; right: 6px;
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--warning);
    border: 2px solid var(--surface);
}

.notif-panel {
    position: absolute;
    right: 0;
    top: calc(100% + var(--space-2));
    width: min(320px, calc(100vw - var(--space-8)));
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-lg);
    padding: var(--space-4);
    z-index: 1070;
}

.notif-panel[hidden] { display: none; }
.notif-head { font-size: 11px; font-weight: 600; letter-spacing: .8px; text-transform: uppercase; color: var(--text-dim); margin-bottom: var(--space-3); }
.notif-empty { margin: 0; font-size: var(--fs-secondary); color: var(--text-dim); }

/* ------------------------------------------------------------------
   SIDEBAR: submenu
   ------------------------------------------------------------------ */

.nav-sub {
    display: block;
    padding: 7px var(--space-3) 7px var(--space-8);
    border-radius: var(--radius-button);
    color: var(--text-dim);
    font-size: 13px;
    margin-bottom: 2px;
    transition: background var(--transition), color var(--transition);
}

.nav-sub:hover { background: var(--surface-hover); color: var(--text-muted); }
.nav-sub.active { color: var(--text); box-shadow: inset 2px 0 0 var(--brand); }

/* ------------------------------------------------------------------
   GRAFIK HARGA
   Digambar sebagai SVG inline dari data yang SUDAH ada di HTML. Tidak ada
   pustaka luar, dan peramban tidak pernah memanggil siapa pun untuk
   menggambarnya.
   ------------------------------------------------------------------ */

.price-chart { width: 100%; height: 200px; display: block; }
.price-chart .grid-line { stroke: var(--border); stroke-width: 1; stroke-dasharray: 3 4; }
.price-chart .axis { stroke: var(--border-strong); stroke-width: 1; }
.price-chart .series { fill: none; stroke: var(--brand); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.price-chart .area { fill: var(--a-brand-10); stroke: none; }
.price-chart .marker { fill: var(--brand); }

.range-tabs { display: flex; gap: var(--space-1); flex-wrap: wrap; }

.range-tab {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 5px var(--space-3);
    border-radius: var(--radius-button);
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-muted);
    font-size: var(--fs-secondary);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}

.range-tab:hover { background: var(--surface-hover); color: var(--text); }
.range-tab.active { background: var(--brand-soft); border-color: var(--a-brand-32); color: var(--brand-hover); }

/* Periode di luar paket TETAP TAMPIL, ditandai terkunci. Menyembunyikannya
   akan menyembunyikan pula apa yang pengguna dapat bila menaikkan paket. */
.range-tab.locked { opacity: .55; cursor: not-allowed; }
.range-tab.locked svg { width: 11px; height: 11px; }

/* ------------------------------------------------------------------
   ALOKASI PORTOFOLIO
   ------------------------------------------------------------------ */

.alloc-row { display: grid; grid-template-columns: 72px 1fr 72px; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); }
.alloc-code { font-weight: 600; letter-spacing: .3px; }
.alloc-track { height: 8px; border-radius: var(--radius-badge); background: var(--bg-elevated); border: 1px solid var(--border); overflow: hidden; }
.alloc-fill { display: block; height: 100%; width: 0; background: var(--brand); transition: width var(--transition); }
.alloc-value { text-align: right; font-variant-numeric: tabular-nums; color: var(--text-muted); font-size: var(--fs-secondary); }

/* ------------------------------------------------------------------
   PENYARING DAFTAR ANALISIS
   ------------------------------------------------------------------ */

.filter-chips { display: flex; gap: var(--space-1); flex-wrap: wrap; }

.filter-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 5px var(--space-3);
    border-radius: var(--radius-badge);
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-muted);
    font-size: var(--fs-secondary);
    font-weight: 600;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}

.filter-chip:hover { background: var(--surface-hover); color: var(--text); }
.filter-chip.active { background: var(--brand-soft); border-color: var(--a-brand-32); color: var(--brand-hover); }
.filter-chip svg { width: 12px; height: 12px; }

/* ------------------------------------------------------------------
   PONSEL
   ------------------------------------------------------------------ */

@media (max-width: 991.98px) {
    .topbar-search { flex: 1 1 100%; margin: 0 var(--space-2); max-width: none; }
    .topbar-title { display: none; }
}

@media (max-width: 575.98px) {
    .topbar-search { display: none; }
    .topbar-title { display: block; }
    .alloc-row { grid-template-columns: 60px 1fr 60px; }
}

/* "Kenapa sinyal ini?" — rincian rule yang dilipat.
   Terlipat secara bawaan: yang ingin tahu membukanya, yang tidak tidak
   perlu melewatinya setiap kali membuka halaman. */
.why-signal { border: 1px solid var(--border); border-radius: var(--radius-button); background: var(--bg-elevated); }
.why-signal > summary {
    cursor: pointer;
    padding: var(--space-3) var(--space-4);
    font-weight: 600;
    font-size: var(--fs-secondary);
    color: var(--text-muted);
    display: flex;
    align-items: center;
    gap: var(--space-2);
    list-style: none;
}
.why-signal > summary::-webkit-details-marker { display: none; }
.why-signal > summary:hover { color: var(--text); }
.why-signal > summary svg { width: 14px; height: 14px; }
.why-signal[open] > summary { border-bottom: 1px solid var(--border); }
.why-signal > *:not(summary) { padding-left: var(--space-4); padding-right: var(--space-4); }
.why-signal > .table-wrap { padding: 0; }
.why-signal > p:last-child { padding-bottom: var(--space-4); }
.why-signal > p:first-of-type { padding-top: var(--space-3); }

/* ==================================================================
   V0.9.1 — KESIAPAN BETA
   Seluruhnya memakai lapis token Midnight Finance. Tidak ada warna baru.
   ================================================================== */

/* ------------------------------------------------------------------
   SPANDUK BETA
   Dapat dimatikan lewat .env. PENAFIAN sinyal, broker, dan data TIDAK
   ikut mati bersamanya — penafian bukan hiasan yang boleh dipadamkan.
   ------------------------------------------------------------------ */

.beta-bar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-6);
    background: var(--warning-soft);
    border-bottom: 1px solid var(--a-warning-32);
    color: var(--warning-text);
    font-size: var(--fs-secondary);
    line-height: 1.4;
}

.beta-bar svg { width: 14px; height: 14px; flex-shrink: 0; }
.beta-bar .beta-text { color: var(--text-muted); }
.beta-bar a { color: var(--warning-text); text-decoration: underline; }
.beta-bar a:hover { color: var(--text); }

.beta-note {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    font-size: var(--fs-secondary);
    color: var(--text-muted);
    margin: 0 0 var(--space-4);
}

@media (max-width: 575.98px) {
    .beta-bar { padding: var(--space-2) var(--space-3); }
}

/* ------------------------------------------------------------------
   UMPAN BALIK BETA
   ------------------------------------------------------------------ */

.feedback-fab {
    position: fixed;
    right: var(--space-5);
    bottom: var(--space-5);
    z-index: 1040;
    box-shadow: var(--shadow-lg);
}

@media (max-width: 575.98px) {
    .feedback-fab { right: var(--space-3); bottom: var(--space-3); }
}

textarea.input-app { min-height: 120px; resize: vertical; font-family: inherit; line-height: 1.55; }

/* ------------------------------------------------------------------
   KESEHATAN SISTEM — tiga tingkat
   OK / WARNING / FAIL dibedakan dengan warna DAN ikon DAN teks.
   ------------------------------------------------------------------ */

.health-ok      { background: var(--positive-soft); color: var(--positive-text); border-color: var(--a-positive-32); }
.health-warning { background: var(--warning-soft);  color: var(--warning-text);  border-color: var(--a-warning-32); }
.health-fail    { background: var(--negative-soft); color: var(--negative-text); border-color: var(--a-negative-32); }

/* ------------------------------------------------------------------
   V0.9.1 — ANAK FLEX DAN GRID HARUS BOLEH MENYUSUT

   Anak sebuah kontainer flex atau grid bernilai `min-width: auto` secara
   bawaan, yang berarti ia MENOLAK menyusut di bawah lebar intrinsik
   isinya. Sebuah tabel lebar di dalam kartu flex karena itu memaksa
   kartunya melebar, lalu memaksa halaman meluber mendatar — meskipun
   tabel itu sudah dibungkus wadah ber-`overflow-x: auto`.

   Ditemukan pada halaman detail saham di lebar 1024px: tabel rincian rule
   selebar 734px memaksa `documentElement.scrollWidth` menjadi 1037.
   ------------------------------------------------------------------ */

.signal-card > *,
.card-app > *,
.chart-card > *,
.metric-card > *,
.usage-card > *,
.state > *,
.why-signal > * {
    min-width: 0;
}

/* Wadah tabel yang dapat digeser tidak boleh ikut melebarkan induknya. */
.table-wrap { max-width: 100%; min-width: 0; }

/* ==================== COMBOBOX PENCARIAN ====================
   Dipakai My Stocks untuk menggantikan dropdown 1.206 opsi. */
.combo { position: relative; }

.combo-list {
    position: absolute;
    z-index: 40;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    margin: 0;
    padding: 4px;
    list-style: none;
    max-height: 280px;
    overflow-y: auto;
    background: var(--color-card);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-input);
    box-shadow: 0 12px 28px var(--a-black-60);
}

.combo-list [role="option"] {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    padding: 8px 10px;
    border-radius: 6px;
    cursor: pointer;
    font-size: 13.5px;
}

.combo-list [role="option"]:hover,
.combo-list [role="option"].is-active {
    background: var(--brand-soft);
}

.combo-code {
    font-family: var(--font-mono, monospace);
    font-weight: 600;
    color: var(--brand);
    flex: none;
    min-width: 62px;
}

.combo-name {
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.combo-empty {
    padding: 10px;
    font-size: 13px;
    color: var(--text-dim);
}
