/* Smooth theme transitions for key surfaces */
.header,
.card,
.modal-content,
.table-container,
.notification-item,
.login-box,
.admin-dropdown,
.column-selector {
    transition: background-color var(--ui-duration) var(--ui-ease), color var(--ui-duration) var(--ui-ease), border-color var(--ui-duration) var(--ui-ease), box-shadow var(--ui-duration) var(--ui-ease);
}

/* [CONTEXT 2] Rekap Jam Pemakaian Service (Modal) */
.usage-hourly-summary {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 10px;
    margin-bottom: 16px;
}

.usage-hourly-summary-card {
    background: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    padding: 10px 12px;
    box-shadow: var(--shadow);
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-height: 80px;
    border-left-width: 4px;
    border-left-style: solid;
    border-left-color: transparent;
}

.usage-hourly-summary-card .label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--secondary-color);
    margin-bottom: 0;
}

.usage-hourly-summary-card .value {
    font-size: 20px;
    font-weight: 700;
    color: var(--text-color);
    line-height: 1.1;
}

.usage-hourly-summary-card .sub {
    font-size: 11px;
    color: var(--secondary-color);
    margin-top: 0;
    line-height: 1.3;
}

.usage-hourly-chart {
    display: grid;
    grid-template-columns: repeat(24, minmax(18px, 1fr));
    gap: 6px;
    align-items: end;
    padding: 16px 10px 12px;
    background: var(--light-color);
    border-radius: 12px;
    border: 1px solid var(--border-color);
    min-height: 220px;
    margin-bottom: 20px;
    overflow-x: auto;
}

.usage-hourly-bar {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    min-width: 18px;
    height: 100%;
    gap: 4px;
}

.usage-hourly-bar-fill {
    width: 100%;
    border-radius: 8px 8px 4px 4px;
    background: linear-gradient(180deg, var(--primary-color), var(--primary-dark));
    transition: height var(--ui-duration) var(--ui-ease);
}

.usage-hourly-bar-count {
    font-size: 10px;
    color: var(--text-color);
    font-weight: 600;
}

.usage-hourly-bar-label {
    font-size: 10px;
    color: var(--secondary-color);
    transform: rotate(-35deg);
    white-space: nowrap;
}

.usage-hourly-lists {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 20px;
}

.usage-hourly-list {
    background: var(--card-bg);
    border-radius: 12px;
    border: 1px solid var(--border-color);
    padding: 12px 16px;
}

.usage-hourly-list h3 {
    font-size: 14px;
    margin-bottom: 10px;
}

.usage-hourly-list ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

.usage-hourly-list li {
    font-size: 13px;
    padding: 6px 0;
    border-bottom: 1px dashed var(--border-color);
    color: var(--text-color);
}

.usage-hourly-list li:last-child {
    border-bottom: none;
}

.usage-hourly-loading {
    text-align: center;
    color: var(--secondary-color);
    font-size: 14px;
    padding: 20px 0;
}

.usage-recap-tabbar {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}

.usage-recap-tab-btn {
    border: 1px solid var(--border-color);
    background: var(--card-bg);
    color: var(--text-color);
    border-radius: 8px;
    font-size: 12px;
    font-weight: 600;
    padding: 8px 12px;
    cursor: pointer;
}

.usage-recap-tab-btn.active {
    background: var(--primary-color);
    border-color: var(--primary-dark);
    color: #fff;
}

.usage-recap-pane {
    display: block;
}

.usage-recap-range-filter {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 10px;
    margin-bottom: 12px;
    align-items: end;
}

.usage-recap-range-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.usage-recap-range-field label {
    font-size: 12px;
    color: var(--secondary-color);
    font-weight: 600;
}

.usage-recap-range-action {
    display: flex;
    align-items: end;
}

/* ==========================================================================
   Grafik batang per reseller (Rekap Pemakaian)
   ==========================================================================

   PALET KATEGORIKAL — jangan diubah sebagian.

   Delapan slot di bawah adalah satu SET yang divalidasi bersama, bukan delapan pilihan warna
   bebas. Yang dijaga: rentang lightness, lantai chroma, jarak antar-slot bersebelahan saat
   disimulasikan buta warna (ΔE >= 8), jarak untuk penglihatan normal (ΔE >= 15), dan kontras
   terhadap permukaan grafik. Mengganti satu hex, atau menukar urutan dua slot, bisa menjatuhkan
   pasangan bersebelahan di bawah ambang — dan itu tidak terlihat dengan mata.

   Hasil validasi set ini (OKLab x100):
     - terang di atas #f8fafc : CVD terburuk 9.1, penglihatan normal terburuk 19.6
     - gelap  di atas #0f172a : CVD terburuk 8.4, penglihatan normal terburuk 19.3
       (juga lolos di atas #121212 milik black-gold dan #0b1020 milik midnight)

   URUTAN SLOT ADALAH MEKANISME KEAMANANNYA, bukan selera: slot ditetapkan menurut peringkat
   pemakaian di `services/usage-reseller-series.js` dan dikunci ke kunci deret, sehingga
   menyembunyikan sebuah deret lewat legend tidak pernah mengecat ulang deret yang tersisa.

   Tiga slot terang (aqua, kuning, magenta) berada di bawah kontras 3:1 terhadap permukaan
   terang. Itu disengaja demi menjaga jarak buta warna, dan ditebus dengan "kelegaan": tampilan
   TABEL selalu tersedia di setiap tab, jadi tidak ada angka yang hanya bisa dibaca lewat warna.

   Slot agregat (Total / Lainnya / Tanpa Reseller) sengaja ABU-ABU — netral, di luar palet
   kategorikal — supaya tidak pernah tertukar dengan reseller sungguhan. */
:root {
    --viz-series-1: #2a78d6;
    --viz-series-2: #eb6834;
    --viz-series-3: #1baf7a;
    --viz-series-4: #eda100;
    --viz-series-5: #e87ba4;
    --viz-series-6: #008300;
    --viz-series-7: #4a3aa7;
    --viz-series-8: #e34948;
    --viz-total: #334155;
    --viz-aggregate: #64748b;
}

/* Ketiga tema gelap proyek. Nilainya BUKAN pembalikan otomatis dari kolom terang — ini delapan
   rona yang sama, di-step ulang untuk permukaan gelap lalu divalidasi ulang sebagai satu set. */
[data-theme="dark"],
[data-theme="black-gold"],
[data-theme="midnight"] {
    --viz-series-1: #3987e5;
    --viz-series-2: #d95926;
    --viz-series-3: #199e70;
    --viz-series-4: #c98500;
    --viz-series-5: #d55181;
    --viz-series-6: #008300;
    --viz-series-7: #9085e9;
    --viz-series-8: #e66767;
    --viz-total: #e2e8f0;
    --viz-aggregate: #94a3b8;
}

/* Legend: satu-satunya pengendali deret mana yang tampil. Selalu ada saat deret >= 2. */
.usage-chart-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 10px;
}

.usage-chart-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border: 1px solid var(--border-color);
    background: var(--card-bg);
    color: var(--text-color);
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    padding: 4px 10px;
    cursor: pointer;
    transition: opacity var(--ui-duration) var(--ui-ease), border-color var(--ui-duration) var(--ui-ease);
}

.usage-chart-legend-item:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* Deret tersembunyi tetap terbaca namanya — dipadamkan, bukan dihapus, supaya user tahu
   apa yang sedang ia sembunyikan dan bisa mengembalikannya. */
.usage-chart-legend-item[aria-pressed="false"] {
    opacity: 0.45;
}

.usage-chart-legend-item[aria-pressed="false"] .usage-chart-legend-swatch {
    background: transparent;
}

.usage-chart-legend-swatch {
    width: 12px;
    height: 12px;
    border-radius: 3px;
    background: var(--series-color, var(--viz-aggregate));
    border: 2px solid var(--series-color, var(--viz-aggregate));
    flex: 0 0 auto;
}

/* Ember "Tanpa Reseller" diberi arsir 45 derajat: pembedanya bukan rona (ia abu-abu, sama
   keluarga dengan "Lainnya") melainkan tekstur — kanal yang tetap terbaca saat dicetak
   hitam-putih maupun pada mode warna paksa. */
.usage-chart-legend-swatch.is-hatched,
.usage-chart-bar.is-hatched {
    background-image: repeating-linear-gradient(
        45deg,
        rgba(255, 255, 255, 0.55) 0,
        rgba(255, 255, 255, 0.55) 2px,
        transparent 2px,
        transparent 5px
    );
}

.usage-chart-legend-value {
    font-variant-numeric: tabular-nums;
    color: var(--secondary-color);
    font-weight: 500;
}

/* Kelompok batang. Grafik lama memakai grid 24/30 kolom; mode berkelompok memakai flex karena
   lebar tiap kelompok bergantung pada BANYAKNYA deret yang sedang tampil, bukan pada jumlah
   kolom yang tetap. Wadahnya sudah `overflow-x: auto`, jadi kelompok yang melebar tinggal
   digeser mendatar alih-alih memampat sampai batangnya hilang. */
.usage-hourly-chart.is-grouped {
    display: flex;
    grid-template-columns: none;

    /* 8px, bukan 10px — angkanya ditentukan aritmetika, bukan selera. Rekap jam menggambar
       24 kelompok dengan lebar batang minimum 26px (dipaksa `has-value-labels` supaya angkanya
       muat): 24x26 + 23 jarak + padding 20. Pada jarak 10px hasilnya 874px, sedangkan bidang
       gambar di dalam `.modal-lg` hanya 858px — meleset 16px, dan satu jam ujung terdorong ke
       luar layar walau deretnya cuma satu. Pada 8px hasilnya 828px, jadi satu hari penuh
       00:00–23:00 muat utuh tanpa digulir sama sekali.
       Dengan dua deret atau lebih grafiknya memang tetap melebihi wadah dan digulir — itu
       pertukaran yang disengaja; yang dijamin di situ adalah pembacaan SELALU dimulai dari
       jam 00 (`initialScrollAnchor: 'start'` di public/js/dashboard/48-usage-stats.js). */
    gap: 8px;
    align-items: flex-end;

    /* Tinggi bidang gambar. Angka PASTI dalam piksel, dan itu bukan selera — lihat catatan
       di `.usage-chart-group-bars`. */
    --usage-chart-plot-height: 180px;
}

.usage-chart-group {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
    gap: 4px;
    flex: 1 0 auto;
    min-width: calc(var(--series-count, 1) * 10px);
}

/* BIDANG GAMBAR — tingginya WAJIB pasti (piksel), jangan diganti `height: 100%` atau `flex: 1`.
   Versi pertama fitur ini memakai `height: 100%` + `min-height`, dan batangnya memakai tinggi
   PERSEN. Dua akibatnya, keduanya membuat tinggi batang berhenti mencerminkan angka:
     - persen butuh tinggi induk yang pasti; saat induknya ikut melar/menyusut mengikuti flex,
       basis persennya bergeser dan hasilnya bukan lagi proporsional terhadap data;
     - baris ini adalah flex item dengan `flex-shrink: 1` bawaan, jadi saat isi kelompok
       melebihi tinggi wadah ia DIPENDEKKAN — seluruh batang termampat ke tinggi yang mirip,
       persis gejala "jumlahnya beda jauh tapi tinggi barnya sama".
   Sekarang tingginya piksel pasti dan batangnya juga diberi tinggi piksel oleh JavaScript.

   Garis bantu horizontal digambar tiap 25% dari dasar. Karena setiap bidang gambar tingginya
   sama dan rata bawah, garisnya sejajar antar kelompok dan terbaca sebagai satu grid. */
.usage-chart-group-bars {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    /* Celah 2px seukuran permukaan memisahkan isian yang bersebelahan supaya dua deret
       tidak pernah terbaca sebagai satu batang lebar. */
    gap: 2px;
    width: 100%;
    height: var(--usage-chart-plot-height);
    flex: 0 0 auto;
    background-image: repeating-linear-gradient(
        to top,
        var(--border-color) 0,
        var(--border-color) 1px,
        transparent 1px,
        transparent 25%
    );
}

/* Satu kolom per batang: angka aktualnya di atas, batangnya menempel garis dasar.
   Slot inilah sasaran hover tooltip — batang bernilai kecil tingginya beberapa piksel dan
   hampir mustahil disasar kursor, sedangkan slot setinggi bidang gambar. */
.usage-chart-bar-slot {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
    gap: 2px;
    height: 100%;
    flex: 1 1 auto;
    min-width: var(--usage-chart-bar-min-width, 6px);
    max-width: 44px;
}

.usage-chart-bar {
    /* Melar hanya pada LEBAR. `flex-shrink` dimatikan supaya tata letak tidak pernah
       memendekkan batang — tingginya milik data, bukan milik flex. */
    flex: 0 0 auto;
    width: 100%;
    max-width: 26px;
    height: var(--bar-height, 0px);
    /* Ujung data membulat 4px, pangkalnya menempel garis dasar. */
    border-radius: 4px 4px 0 0;
    background-color: var(--series-color, var(--viz-aggregate));
    transition: height var(--ui-duration) var(--ui-ease);
}

/* Angka aktual di atas batang. Memakai token teks, bukan warna deretnya: identitas dibawa
   tanda berwarna di sebelahnya, angka tetap tinta biasa supaya selalu terbaca. */
.usage-chart-bar-value {
    flex: 0 0 auto;
    font-size: 9px;
    line-height: 1;
    font-weight: 600;
    color: var(--text-color);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Porsi deret terhadap TOTAL bucket-nya, satu baris di bawah jumlahnya.
   Sengaja lebih kecil dan lebih redup daripada jumlahnya: jumlah adalah angka utama, persentase
   adalah pembacanya. Ukurannya juga yang membuat "100%" tetap muat di lebar batang minimum 26px,
   jadi menambahkan baris ini TIDAK melebarkan grafik dan satu hari penuh tetap muat. */
.usage-chart-bar-share {
    flex: 0 0 auto;
    font-size: 8px;
    line-height: 1;
    font-weight: 600;
    color: var(--secondary-color);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    margin-top: 1px;
}

/* Persentase di legend & tabel: porsi deret terhadap SELURUH rentang, bukan terhadap satu bucket. */
.usage-chart-legend-share,
.usage-chart-table-share {
    font-size: 11px;
    font-weight: 600;
    color: var(--secondary-color);
    font-variant-numeric: tabular-nums;
}

.usage-chart-legend-share::before {
    content: "•";
    margin: 0 4px;
    color: var(--border-color);
}

/* Menyalakan angka MELEBARKAN batang supaya angkanya muat; tanpa ini label saling bertumpuk.
   Grafiknya jadi lebih lebar dari wadah dan digulir mendatar — pertukaran yang disengaja,
   dan bisa dibatalkan lewat tombol "Sembunyikan angka".
   Pita angkanya ditambahkan DI ATAS bidang gambar, bukan memotong jatahnya, supaya tinggi
   batang tidak berubah saat label dinyalakan/dimatikan. */
.usage-hourly-chart.is-grouped.has-value-labels {
    --usage-chart-bar-min-width: 26px;
}

.usage-hourly-chart.is-grouped.has-value-labels .usage-chart-group-bars {
    height: calc(var(--usage-chart-plot-height) + 26px);
    background-position: bottom;
    background-size: 100% var(--usage-chart-plot-height);
    background-repeat: no-repeat;
}

/* Batang bernilai nol tetap disisakan setipis rambut: tanpa itu kelompoknya menyempit dan
   posisi deret bergeser antar kelompok, sehingga warna yang sama tidak lagi sejajar. */
.usage-chart-bar.is-zero {
    height: 2px;
    opacity: 0.35;
}

.usage-chart-group-label {
    font-size: 10px;
    color: var(--secondary-color);
    transform: rotate(-35deg);
    white-space: nowrap;
}

/* Catatan mengambil sisa ruang supaya tombol-tombol terdorong rapat ke kanan tanpa perlu
   wadah pembungkus tersendiri di markup. */
.usage-chart-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 8px;
}

.usage-chart-note {
    flex: 1 1 200px;
    font-size: 11px;
    color: var(--secondary-color);
}

/* Tampilan tabel — kelegaan wajib untuk slot berkontras rendah, sekaligus jalan baca bagi
   pengguna pembaca layar yang tidak bisa menafsirkan tinggi batang. */
.usage-chart-table-wrap {
    max-height: 260px;
    overflow: auto;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    margin-bottom: 16px;
}

.usage-chart-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
}

.usage-chart-table th,
.usage-chart-table td {
    padding: 6px 10px;
    text-align: right;
    white-space: nowrap;
    border-bottom: 1px solid var(--border-color);
    font-variant-numeric: tabular-nums;
}

.usage-chart-table th:first-child,
.usage-chart-table td:first-child {
    text-align: left;
    position: sticky;
    left: 0;
    background: var(--card-bg);
    font-variant-numeric: normal;
}

.usage-chart-table thead th {
    position: sticky;
    top: 0;
    background: var(--table-header-bg);
    color: var(--table-header-text);
    z-index: 1;
}

.usage-chart-table thead th:first-child {
    z-index: 2;
    background: var(--table-header-bg);
    color: var(--table-header-text);
}
