.mr-0,
.mx-0 {
  margin-right: 0 !important;
}

.mr-1,
.mx-1 {
  margin-right: 0.25rem !important;
}

.mr-2,
.mx-2 {
  margin-right: 0.5rem !important;
}

.mr-3,
.mx-3 {
  margin-right: 1rem !important;
}

.mr-4,
.mx-4 {
  margin-right: 1.5rem !important;
}

.mr-5,
.mx-5 {
  margin-right: 3rem !important;
}

.ml-0,
.mx-0 {
  margin-left: 0 !important;
}

.ml-1,
.mx-1 {
  margin-left: 0.25rem !important;
}

.ml-2,
.mx-2 {
  margin-left: 0.5rem !important;
}

.ml-3,
.mx-3 {
  margin-left: 1rem !important;
}

.ml-4,
.mx-4 {
  margin-left: 1.5rem !important;
}

.ml-5,
.mx-5 {
  margin-left: 3rem !important;
}

/* =====================================================================
   Tata letak sidebar
   =====================================================================

   Tabler menggeser konten dengan selektor saudara
   (.navbar-vertical.navbar-expand-lg ~ .page-wrapper), tapi setiap view
   di sini membungkus isinya dengan <div class="wrapper"> lebih dulu —
   dan satu view (soal/view-soal.php) bahkan menambah satu lapis lagi.
   Karena itu pergeserannya dipasang langsung pada .wrapper.

   .wrapper hanya ada di halaman yang memuat sidebar; halaman login
   memakai header-signin.php dan tidak punya elemen ini, jadi aturan
   global di bawah tidak mengenainya.
   ===================================================================== */
@media (min-width: 992px) {
  .wrapper {
    padding-left: 15rem;
  }
}

/* Label pemisah kelompok di sidebar.
   Warnanya diatur di bagian palet paling bawah berkas ini — label ini
   memakai kelas .nav-link juga, jadi keduanya harus diputuskan di satu
   tempat supaya tidak saling menimpa tanpa disengaja. */
.navbar-vertical .sidebar-label {
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  pointer-events: none;
  padding-bottom: 0.25rem;
}

/* Isi sidebar didorong ke atas, blok identitas admin menempel ke bawah */
.navbar-vertical .navbar-collapse {
  display: flex;
  flex-direction: column;
}

.navbar-vertical .navbar-nav {
  width: 100%;
}

/* Judul halaman di bilah atas */
.navbar-brand-title .h3 {
  color: #354052;
}

/* Tabel lebar tidak boleh memaksa seluruh halaman menggulir mendatar */
.card-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* =====================================================================
   Tabel admin yang menggulir sendiri
   =====================================================================

   Tabel Hasil punya 13 kolom bertanda text-nowrap. Sebelumnya ia meluber
   keluar kartu, membuat SELURUH halaman bisa digulir mendatar — dan
   karena sidebar position:fixed diam di tepi layar, tabelnya lewat di
   bawah sidebar saat digulir. Wadah di bawah mengurung gulirnya di dalam
   kartu, sehingga halamannya sendiri tidak pernah bergeser.
   ===================================================================== */
.tabel-gulir {
  overflow-x: auto;
  overflow-y: auto;
  max-height: 70vh;
  -webkit-overflow-scrolling: touch;
}

/* Judul kolom tetap terlihat saat isinya digulir. Latarnya WAJIB buram —
   dengan latar bening, baris yang lewat di belakangnya akan menembus. */
.tabel-gulir thead th {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: 2;
  background: #f8fafc;
}

/* Kolom aksi dipatok di tepi kanan, supaya tombolnya tetap terjangkau
   berapa pun tabel digulir ke kanan. */
.tabel-gulir th.kolom-aksi,
.tabel-gulir td.kolom-aksi {
  position: -webkit-sticky;
  position: sticky;
  right: 0;
  z-index: 1;
  background: #fff;
  box-shadow: -6px 0 6px -6px rgba(0, 0, 0, .18);
}

/* Sel sudut : menempel ke atas DAN ke kanan sekaligus, jadi z-index-nya
   harus di atas keduanya. Tanpa ini ia tertimpa salah satu. */
.tabel-gulir thead th.kolom-aksi {
  z-index: 3;
  background: #f8fafc;
}

/* Baris belang tetap terbaca di kolom yang menempel */
.tabel-gulir tbody tr:hover td.kolom-aksi {
  background: #f8fafc;
}

/* =====================================================================
   Tombol aksi pada tabel
   =====================================================================

   Kolom aksi sengaja TIDAK memakai dropdown. Wadah .tabel-gulir memotong
   apa pun yang keluar dari kotaknya, dan sel .kolom-aksi baris di bawahnya
   — sticky, z-index sama, lebih belakang di DOM — menggambar di atas menu
   yang sedang terbuka. Deretan tombol tanpa popup menghapus kedua persoalan
   itu sekaligus, dan menghemat satu klik.
   ===================================================================== */
.aksi-sel {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .25rem;
}

.aksi-baris {
  display: flex;
  align-items: center;
  gap: .25rem;
  flex-wrap: nowrap;
}

/* Bidang tekan minimal 34px : ikon 20px saja terlalu kecil untuk jari. */
.btn-aksi {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  height: 34px;
  padding: .25rem .4rem;
  line-height: 1;
}

.btn-aksi .ikon-aksi {
  width: 20px;
  height: 20px;
  vertical-align: middle;
}

/* Aksi merusak diberi jarak, supaya tidak tertekan karena meleset */
.aksi-baris .aksi-pisah {
  margin-left: .35rem;
}

/* Tombol catatan pada baris yang catatannya kosong : terlihat ada, jelas
   tidak bisa ditekan. */
.btn-aksi:disabled {
  opacity: .35;
  cursor: default;
}

/* =====================================================================
   Menu aksi di ponsel
   =====================================================================

   Di bawah 768px seluruh isi sel aksi diganti SATU tombol hamburger yang
   memunculkan popup berisi daftar aksi tegak, lengkap dengan tulisannya.
   Tombolnya disisipkan ke setiap .aksi-sel oleh myjs/function.js pada
   peristiwa draw.dt.

   Pemicunya SELALU ada di DOM berapa pun lebar layarnya; yang mengatur
   tampil-tidaknya cuma media query di bawah. Dengan begitu memutar layar
   atau mengubah ukuran jendela tidak bisa meninggalkan baris dalam
   keadaan setengah jadi.

   GAYANYA MENGIKUTI POPUP SKOR, dan itu disengaja.
   Keduanya muncul di ponsel pada halaman yang berdekatan, jadi keduanya
   harus terbaca sebagai satu keluarga: kotak melayang di tengah berisi
   kartu-kartu berbingkai yang saling berjarak. Nilai bingkai, radius, dan
   latarnya diambil dari .skor-popup-baris di bawah berkas ini — kalau
   salah satunya diubah, ubah keduanya. uji_aksi_lembar.js menegakkan
   keduanya tetap sama.

   CATATAN NAMA : kelas di sini masih berawalan "lembar-aksi" karena
   versi pertamanya memang lembar yang menempel di tepi bawah. Bentuk itu
   sudah ditinggalkan, tapi namanya sengaja tidak diganti — penggantian
   menyentuh lima berkas termasuk dua rangkaian uji tanpa satu pun
   perubahan yang terlihat pemakai.
   ===================================================================== */

/* Ukurannya sengaja 40px, bukan 34px seperti .btn-aksi : ini satu-satunya
   tombol yang tersisa di ponsel, jadi bidang tekannya bidang tekan jari. */
.btn-menu-aksi {
  display: none;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  height: 40px;
  padding: .25rem .4rem;
  line-height: 1;
  border-radius: .5rem;
}

.btn-menu-aksi .ikon-aksi {
  width: 20px;
  height: 20px;
  vertical-align: middle;
}

/* Posisi dan bentuk kotaknya TIDAK diatur di sini sama sekali.
   Keduanya datang dari modal-dialog-centered + modal-sm di markup-nya,
   sama persis dengan #skorPeserta. Aturan lembar bawah yang dulu ada di
   tempat ini — position: fixed, translateY(100%), radius hanya di atas,
   safe-area-inset-bottom — sudah dibuang seluruhnya; menyisakan sebagian
   berarti dua aturan posisi saling menimpa. */

.lembar-aksi-judul {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Pembungkusnya sama dengan .skor-popup : kolom, berjarak .5rem.
   Jarak itulah yang memisahkan butir — bukan garis. */
.lembar-aksi-daftar {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

/* Kartu, bukan baris. Bingkai, radius, dan latarnya SAMA PERSIS dengan
   .skor-popup-baris — lihat catatan di kepala blok ini.

   Ikon lalu tulisan, keduanya rata kiri pada satu garis tegak, supaya
   daftarnya terbaca lurus dan tidak berundak. */
.lembar-aksi-butir {
  display: flex;
  gap: .85rem;
  align-items: center;
  width: 100%;
  padding: .65rem .85rem;
  border: 1px solid var(--ui-garis);
  border-radius: .5rem;
  background: var(--ui-permukaan);
  color: var(--ui-navy-2);
  font-size: .9375rem;
  text-align: left;
  text-decoration: none;
}

.lembar-aksi-butir:hover,
.lembar-aksi-butir:focus {
  border-color: var(--ui-aksen);
  background: var(--ui-latar);
  color: var(--ui-navy-2);
  text-decoration: none;
}

.lembar-aksi-butir:disabled {
  opacity: .4;
  cursor: default;
}

/* Lebar ikonnya dipatok supaya seluruh tulisan mulai di kolom yang sama.
   Tanpa flex-shrink: 0 ikon yang lebih lebar akan menggeser tulisannya dan
   daftarnya berhenti terlihat lurus. */
.lembar-aksi-ikon {
  display: inline-flex;
  flex: 0 0 24px;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  color: var(--ui-aksen);
}

/* SVG-nya salinan dari tombol di baris, jadi masih membawa .ikon-aksi yang
   berukuran 20px. Di dalam popup ukurannya ditentukan di sini. */
.lembar-aksi-ikon svg {
  width: 24px;
  height: 24px;
}

.lembar-aksi-teks {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Aksi merusak : kartu bernada merah, ditaruh paling bawah.
   Tidak ada garis pemisah — popup skor juga tidak punya, dan jaraknya
   sudah cukup memisahkan. Jarak tambahan di atasnya yang menjaga maksud
   "jangan sampai salah tekan" dari .aksi-baris .aksi-pisah. */
.lembar-aksi-butir.lembar-aksi-merusak {
  margin-top: .35rem;
  border-color: var(--ui-bahaya);
  background: #fef2f2;
  color: var(--ui-bahaya);
}

.lembar-aksi-butir.lembar-aksi-merusak .lembar-aksi-ikon {
  color: var(--ui-bahaya);
}

.lembar-aksi-butir.lembar-aksi-merusak:hover,
.lembar-aksi-butir.lembar-aksi-merusak:focus {
  border-color: var(--ui-bahaya);
  background: #fee2e2;
  color: var(--ui-bahaya);
}

@media (max-width: 767.98px) {
  /* SELURUH isi sel disembunyikan, bukan hanya .btn-aksi : tombol Salin
     Link di halaman Tes memakai .copy .btn-warning dan tidak pernah
     membawa .btn-aksi, jadi menyaring kelas akan meninggalkannya sendirian
     di baris. Kekhususan 0,2,0 mengalahkan .btn-aksi dan .aksi-baris yang
     masing-masing cuma 0,1,0. */
  .aksi-sel > *:not(.btn-menu-aksi) {
    display: none;
  }

  .aksi-sel .btn-menu-aksi {
    display: inline-flex;
  }

  /* Kolomnya menyusut dari ±150px jadi ±46px. Patokan sticky-nya DIPERTAHANKAN
     justru karena sekarang sempit: tabelnya jadi lebih lebar setelah kolom
     d-none dimunculkan, dan tanpa patokan tombol aksinya baru terjangkau
     setelah menggulir jauh ke kanan. Yang dulu terasa "statis dan tidak
     nyaman" adalah kolom selebar 150px, bukan satu tombol 46px. */
  .tabel-gulir th.kolom-aksi,
  .tabel-gulir td.kolom-aksi {
    width: 1%;
  }
}

/* Isi popup catatan.
   pre-wrap wajib : catatan sering diketik berbaris-baris, dan tanpa ini
   seluruhnya runtuh jadi satu paragraf panjang. break-word menahan
   tempelan URL panjang supaya tidak melebarkan modalnya. */
.catatan-isi {
  white-space: pre-wrap;
  overflow-wrap: break-word;
  word-break: break-word;
  line-height: 1.55;
}

/* =====================================================================
   Kolom nama
   =====================================================================

   Sebelumnya beberapa tabel memasang text-nowrap pada SELURUH elemen
   <table>. Akibatnya nama peserta tidak pernah boleh membungkus, jadi
   kolomnya melebar sepanjang nama terpanjang di halaman itu dan
   mendorong seluruh kolom lain keluar layar. Memberi width pada
   kolomnya tidak menolong selama nowrap masih di sana; yang dibuang
   nowrap-nya, lalu lebarnya dibatasi di sini.

   min-width menjaga kolomnya tidak menyempit sampai satu kata per baris
   ketika tabelnya padat.
   ===================================================================== */
.kolom-nama {
  max-width: 18rem;
  min-width: 9rem;
  white-space: normal;
  overflow-wrap: break-word;   /* nama tanpa spasi tetap terpotong rapi */
  word-break: break-word;
  line-height: 1.35;
}

@media (max-width: 575.98px) {
  .kolom-nama { max-width: 11rem; }
}

/* Kepala tabel bergaya acuan : kecil, kapital, redup */
.tabel-gulir thead th {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-weight: 700;
  color: #6c757d;
  white-space: nowrap;
  vertical-align: middle;
}

/* Pengendali DataTables (pencarian, jumlah baris, halaman) tidak boleh
   ikut terkurung di dalam wadah yang menggulir */
.dataTables_wrapper .dataTables_filter,
.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_paginate {
  padding: .5rem .25rem;
}

/* =====================================================================
   Pemilih paket soal
   ===================================================================== */

.paket-kotak {
  border: 1px solid #e6e9ee;
  border-radius: .5rem;
  overflow: hidden;
  height: 100%;
}

.paket-kepala {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .65rem;
  background: #f8f9fa;
  border-bottom: 1px solid #e6e9ee;
  font-size: .78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: #6c757d;
}

.paket-kepala .paket-cari {
  margin-left: auto;
  max-width: 9rem;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
}

.paket-daftar,
.paket-urutan {
  max-height: 15rem;
  overflow-y: auto;
}

/* --- sisi kiri : centang --- */
.paket-tersedia {
  display: flex;
  align-items: center;
  gap: .6rem;
  width: 100%;
  min-height: 44px;              /* bidang tekan yang nyaman di layar sentuh */
  margin: 0;
  padding: .45rem .65rem;
  border-bottom: 1px solid #f1f3f6;
  cursor: pointer;
}

.paket-tersedia:hover { background: #f8fafc; }

/* Kotak centang tidak boleh ikut menyusut.
   Tanpa ini, paket bernama panjang ("L Barron 03 S Longman 05 R Longman 04")
   membungkus jadi tiga baris dan flex memampatkan kotaknya sampai gepeng —
   terlihat rusak, dan bidang tekannya jadi terlalu kecil untuk jari. */
.paket-tersedia .form-check-input {
  flex: 0 0 auto;
  margin: 0;
}

/* Nama yang membungkus tetap sejajar dengan kotaknya di baris pertama */
.paket-tersedia { align-items: flex-start; }

.paket-nama   { flex: 1 1 auto; }
.paket-jumlah {
  color: #8a94a6;
  font-size: .78rem;
  white-space: nowrap;
  flex: 0 0 auto;          /* "140 soal" tidak ikut terpotong */
}

/* --- sisi kanan : urutan --- */
.paket-baris {
  display: flex;
  align-items: center;
  gap: .5rem;
  min-height: 44px;
  padding: .35rem .5rem;
  border-bottom: 1px solid #f1f3f6;
  background: #fff;
}

.paket-baris.sedang-diseret {
  background: #eef3fb;
  border-radius: .35rem;
}

/* Gagang seret. touch-action WAJIB none — tanpa itu peramban merebut gerak
   jari untuk menggulir dan urutannya tidak pernah berpindah di layar
   sentuh, persis seperti yang pernah terjadi di perancang sertifikat. */
.paket-gagang {
  touch-action: none;
  cursor: grab;
  color: #b3bcc9;
  letter-spacing: -3px;
  padding: 0 .25rem;
  user-select: none;
}

.paket-gagang:active { cursor: grabbing; }

.paket-urut {
  flex: 0 0 auto;
  width: 1.5rem;
  height: 1.5rem;
  line-height: 1.5rem;
  text-align: center;
  border-radius: 50%;
  background: #206bc4;
  color: #fff;
  font-size: .75rem;
  font-weight: 700;
}

.paket-label  { flex: 1 1 auto; }
.paket-tombol { flex: 0 0 auto; white-space: nowrap; }

.paket-tombol .btn {
  padding: .1rem .4rem;
  line-height: 1.2;
}

.paket-kosong {
  padding: 1.25rem .65rem;
  text-align: center;
  color: #8a94a6;
  font-size: .85rem;
}

/* =====================================================================
   Panel anti-cheat pada form tes
   ===================================================================== */

/* Menjorok dengan garis tepi merah, meniru susunan acuan : opsi di
   dalamnya jelas milik sakelar induk di atasnya, bukan setelan sejajar. */
.anticheat-opsi {
  margin-left: .5rem;
  padding-left: .85rem;
  border-left: 3px solid #d63939;
  transition: opacity .15s ease;
}

.anticheat-butir {
  display: flex;
  align-items: flex-start;
  gap: .1rem;
  min-height: 34px;
  margin-bottom: .5rem;
}

/* Kotak sakelar tidak boleh menyusut saat keterangannya membungkus */
.anticheat-butir .form-check-input {
  flex: 0 0 auto;
  margin-top: .15rem;
}

.anticheat-butir .alert-icon {
  width: 18px;
  height: 18px;
  vertical-align: text-bottom;
}

/* =====================================================================
   Blok hak akses pada form admin
   ===================================================================== */

.izin-daftar {
  border: 1px solid #e6e9ee;
  border-radius: .5rem;
  padding: .5rem .75rem;
  max-height: 17rem;
  overflow-y: auto;
  transition: opacity .15s ease;
}

.izin-kelompok + .izin-kelompok {
  margin-top: .65rem;
  padding-top: .5rem;
  border-top: 1px solid #f1f3f6;
}

.izin-judul {
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: #8a94a6;
  margin-bottom: .25rem;
}

/* Bidang tekan yang nyaman di layar sentuh */
.izin-butir {
  display: flex;
  align-items: center;
  min-height: 34px;
  margin-bottom: 0;
}

/* =====================================================================
   Perancang sertifikat
   ===================================================================== */

/* Tanpa ini seret di layar sentuh tidak berfungsi sama sekali.
   Peramban memperlakukan setiap gerak jari sebagai perintah menggulir
   dan membatalkan rangkaian pointer sebelum pointermove sempat berguna,
   sehingga elemen tidak pernah ikut bergerak. */
.desain-el {
  touch-action: none;
}

/* menyeret elemen tidak menyorot teks di sekitarnya */
#kanvas,
#kanvas * {
  -webkit-user-select: none;
  user-select: none;
}

/* =====================================================================
   Kartu pemantauan (tampilan ponsel)
   ===================================================================== */

.kartu-pantau {
  border-left: 3px solid transparent;
}

.kartu-pantau-putus { border-left-color: #f59f00; }
.kartu-pantau-awas  { border-left-color: #d63939; }

/* Tiga angka utama dibagi rata : sesi, terjawab, sisa waktu */
.kartu-pantau-angka > div {
  flex: 1 1 0;
  text-align: center;
}

.kartu-pantau-angka .nilai {
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
  color: #354052;
}

.kartu-pantau-angka .label {
  font-size: .72rem;
  color: #8a94a6;
}

.kartu-pantau-progres {
  height: 4px;
  border-radius: 2px;
  background: #edf1f6;
  overflow: hidden;
}

.kartu-pantau-progres > span {
  display: block;
  height: 100%;
  background: #206bc4;
  transition: width .25s ease;
}

/* Pemberitahuan pengganti kanvas di layar sempit */
.desain-sempit {
  border: 1px dashed #c7d0db;
  border-radius: .5rem;
  padding: 1.25rem;
  text-align: center;
  color: #667382;
  background: #f7f9fc;
}

/* Pesan sesaat, ditampilkan mengambang dari _partials/footer.php.

   Dipasang di KANAN BAWAH, bukan kanan atas : di kanan atas ia menimpa
   tombol aksi halaman (Tambahkan Tes) dan, di layar sempit, butir
   sidebar. Sudut kanan bawah tidak pernah berisi kendali apa pun. */
.pesan-flash {
  position: fixed;
  bottom: 1rem;
  right: 1rem;
  z-index: 1080;
  width: 24rem;
  max-width: calc(100vw - 2rem);
  transition: opacity .35s ease, transform .35s ease;
}

/* Keadaan saat menghilang sendiri setelah beberapa detik */
.pesan-flash.pudar {
  opacity: 0;
  transform: translateY(.5rem);
  pointer-events: none;
}

.pesan-flash .alert {
  margin-bottom: 0;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .18);
}

/* Kartu pintasan di bawah tabel dashboard */
.card-pintasan {
  transition: border-color .15s ease, box-shadow .15s ease;
}

.card-pintasan:hover {
  border-color: #206bc4;
  box-shadow: 0 2px 10px rgba(32, 107, 196, .12);
}

.pintasan-label {
  font-weight: 600;
  line-height: 1.25;
}

/* Kartu ringkas dashboard */
.stat-card .stat-nilai {
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.1;
}

.stat-card .stat-label {
  font-size: 0.8rem;
  color: #6c7a91;
}

/* =====================================================================
   PALET & PERMUKAAN
   =====================================================================

   Lapis ini dimuat SESUDAH seluruh berkas Tabler (lihat urutan <link> di
   _partials/header.php), jadi cukup menimpa dari sini — tabler.min.css
   tidak perlu disentuh sama sekali, dan pembaruan Tabler tidak akan
   menghapus perubahan ini.

   Token yang sama, dengan nilai yang sama, juga ada di aplikasi peserta
   (assets/mycss/tes.css). Kalau salah satu diubah, ubah keduanya —
   uji_ui_palet.js membandingkannya dan akan gagal kalau menyimpang.
   ===================================================================== */

:root {
  --ui-navy:       #0f172a;   /* sidebar, permukaan gelap */
  --ui-navy-2:     #1e293b;   /* teks utama */
  --ui-aksen:      #2563eb;   /* tombol utama, tautan, butir aktif */
  --ui-aksen-2:    #3b82f6;   /* hover */
  --ui-sukses:     #10b981;
  --ui-bahaya:     #dc2626;
  --ui-peringatan: #f59e0b;
  --ui-latar:      #f1f5f9;   /* latar halaman */
  --ui-permukaan:  #ffffff;   /* kartu, modal, form */
  --ui-garis:      #e2e8f0;
  --ui-redup:      #64748b;
  --ui-radius:     .75rem;
  --ui-bayang:     0 1px 3px rgba(15, 23, 42, .06), 0 1px 2px rgba(15, 23, 42, .04);
  --ui-bayang-lg:  0 10px 15px -3px rgba(15, 23, 42, .07), 0 4px 6px -4px rgba(15, 23, 42, .05);
  --ui-huruf:      'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}

/* Tumpukan cadangan ditulis penuh : Inter dimuat dari Google Fonts, dan
   kalau CDN-nya tidak terjangkau halaman harus tetap wajar, bukan jatuh
   ke serif bawaan peramban. */
body {
  font-family: var(--ui-huruf);
  background-color: var(--ui-latar);
  color: var(--ui-navy-2);
  -webkit-font-smoothing: antialiased;
}

.page-title,
h1, h2, h3, h4, h5, h6 {
  color: var(--ui-navy-2);
  letter-spacing: -.01em;
}

.text-muted { color: var(--ui-redup) !important; }

a { color: var(--ui-aksen); }
a:hover { color: var(--ui-aksen-2); }

/* ---------------------------------------------------------------------
   Sidebar dongker
   ---------------------------------------------------------------------

   Tabler memberi .navbar-light latar putih; di sini dibalik jadi gelap.
   Selektornya dipatok ke .navbar-vertical supaya bilah atas halaman
   (navbar-header) tidak ikut menggelap.
   --------------------------------------------------------------------- */

.navbar-vertical.navbar-light {
  background: var(--ui-navy);
  border-right: 0;
  box-shadow: inset -1px 0 0 rgba(255, 255, 255, .04);
}

.navbar-vertical .navbar-brand {
  padding-top: 1.25rem;
  padding-bottom: 1.25rem;
}

/* =====================================================================
   KEKHUSUSAN DI BAWAH INI WAJIB SETINGGI ITU. JANGAN DISEDERHANAKAN.
   =====================================================================

   Tabler menyetel warna butir menu lewat:

       .navbar .navbar-nav .nav-link        { color: rgba(35,46,60,.7) }   k=30
       .navbar .navbar-nav .nav-link:hover  { color: #232e3c }             k=40

   Keduanya dirancang untuk sidebar TERANG. Di atas latar dongker kita,
   rgba(35,46,60,.7) menghasilkan rgb(29,39,55) — kontrasnya 1,19:1
   terhadap latar, yaitu praktis tidak terbaca.

   Versi pertama perombakan ini memakai `.navbar-vertical .nav-link`
   (k=20). Kekhususannya di bawah 30, jadi warnanya TIDAK PERNAH terpakai
   dan seluruh menu tenggelam ke dalam latar. Yang terlihat benar cuma
   butir aktif, karena kebetulan kekhususannya 40.

   Karena itu setiap aturan di bawah dipatok ke
   `.navbar-vertical.navbar-light .navbar-nav ...` — semua kelas itu
   memang sudah ada di markup (_partials/sidebar.php), jadi ini bukan
   kekhususan yang dibuat-buat, dan tidak perlu !important.

   uji_ui_render.js menyelesaikan kaskade yang sesungguhnya dan akan
   gagal kalau salah satu aturan ini kembali kalah.
   ===================================================================== */

/* k=40, mengalahkan .navbar .navbar-nav .nav-link (k=30) */
.navbar-vertical.navbar-light .navbar-nav .nav-link {
  color: #cbd5e1;
  border-radius: .5rem;
  margin: .1rem .5rem;
  padding-top: .5rem;
  padding-bottom: .5rem;
  transition: background-color .15s ease, color .15s ease;
}

/* k=50, mengalahkan .navbar .navbar-nav .nav-link:hover (k=40).
   Tanpa ini menyorot butir justru MENGGELAPKAN teksnya. */
.navbar-vertical.navbar-light .navbar-nav .nav-link:hover,
.navbar-vertical.navbar-light .navbar-nav .nav-link:focus {
  color: #ffffff;
  background: rgba(255, 255, 255, .06);
}

/* Butir aktif : latar aksen transparan + penanda kiri, bukan blok penuh —
   supaya tetap terbaca sebagai bagian dari sidebar, bukan tombol.

   k=50. Versi sebelumnya k=40, yang hanya menang karena seri melawan
   Tabler lalu diputus urutan berkas — benar, tapi bergantung pada
   sesuatu yang mudah berubah. */
.navbar-vertical.navbar-light .navbar-nav .nav-item.active > .nav-link,
.navbar-vertical.navbar-light .navbar-nav .nav-link.active {
  color: #ffffff;
  background: rgba(37, 99, 235, .22);
  box-shadow: inset 3px 0 0 var(--ui-aksen-2);
}

/* Ikon mewarisi currentColor, jadi ikut terang sendiri. Opacity dibuat
   penuh supaya tidak meredupkannya lagi. */
.navbar-vertical.navbar-light .navbar-nav .nav-link .nav-link-icon { opacity: 1; }

/* Label kelompok memakai kelas .nav-link juga, jadi ia ikut kalah dari
   Tabler dengan cara yang sama. k=50, dan sengaja lebih redup daripada
   butir menu supaya tetap terbaca sebagai pemisah — tapi 6,96:1, bukan
   3,75:1 seperti sebelumnya. */
.navbar-vertical.navbar-light .navbar-nav .nav-link.sidebar-label {
  color: #94a3b8;
  background: transparent;
  padding-left: 1rem;
  margin-top: .75rem;
}

.navbar-vertical .dropdown-menu {
  background: #16233b;
  border-color: rgba(255, 255, 255, .08);
}

/* =====================================================================
   Submenu Pengaturan
   =====================================================================

   Kekhususannya sengaja disamakan dengan aturan sidebar di atas (0,4,0 /
   0,5,0). Aturan Tabler `.navbar .navbar-nav .nav-link` bernilai 0,3,0 dan
   akan menang atas selektor yang lebih pendek — itu pernah membuat warna
   sidebar saya tidak pernah terpakai sama sekali.
   ===================================================================== */

/* Butir anak dilekukkan supaya hubungan induk-anaknya terbaca, dan dibuat
   sedikit lebih kecil agar tidak bersaing dengan butir menu utama. */
.navbar-vertical.navbar-light .submenu-aturan .navbar-nav .nav-link {
  padding-left: 3rem;
  font-size: .875rem;
}

/* Garis tipis di sisi kiri : penanda visual bahwa keenamnya satu kelompok,
   tanpa menambah kotak atau latar yang membuat sidebar ramai. */
.navbar-vertical .submenu-aturan {
  box-shadow: inset 2px 0 0 rgba(255, 255, 255, .10);
  margin-left: 1.15rem;
}

/* Tanda panah pemicu, berputar saat submenunya terbentang.
   aria-expanded diurus Bootstrap, jadi itu yang dipakai sebagai sumber
   kebenaran — bukan kelas tambahan yang harus disinkronkan sendiri. */
.nav-link-toggle {
  width: 0;
  height: 0;
  border-top: 5px solid currentColor;
  border-right: 4px solid transparent;
  border-left: 4px solid transparent;
  opacity: .7;
  transition: transform .15s ease-in-out;
}

.navbar-vertical .nav-link[aria-expanded="false"] .nav-link-toggle {
  transform: rotate(-90deg);
}

.navbar-vertical .dropdown-item { color: #94a3b8; }
.navbar-vertical .dropdown-item:hover {
  color: #ffffff;
  background: rgba(255, 255, 255, .06);
}

/* =====================================================================
   LACI MENU DI PONSEL
   =====================================================================

   SELURUH bagian ini terkurung di dalam @media (max-width: 991.98px).
   Di 992px ke atas tidak ada satu pun aturan di sini yang berlaku, jadi
   tampilan desktop persis seperti sebelumnya.

   992px dipilih supaya cocok dengan navbar-expand-lg milik <aside> :
   itulah titik di mana Tabler sendiri berhenti melipat sidebarnya.
   ===================================================================== */

@media (max-width: 991.98px) {

  /* Sidebar keluar dari aliran halaman dan menjadi panel yang digeser.
     transform, bukan left/width : hanya transform yang tidak memaksa
     perhitungan tata letak ulang di tiap bingkai animasi. */
  .navbar-vertical.navbar-light {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 1045;             /* di atas .sticky-top (1020), di bawah modal (1050) */
    width: 16rem;
    max-width: 85vw;           /* di layar sangat sempit, isi di belakang tetap terlihat */
    padding: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    transform: translateX(-100%);
    transition: transform .22s ease-out;
  }

  body.laci-buka .navbar-vertical.navbar-light { transform: translateX(0); }

  /* #sidebar-menu masih membawa kelas .collapse milik Bootstrap, yang
     berarti display:none di bawah 992px. Karena tombolnya tidak lagi
     memakai mekanisme collapse, isinya dipaksa terlihat di sini —
     yang menyembunyikannya sekarang adalah transform lacinya. */
  .navbar-vertical .navbar-collapse.collapse {
    display: block !important;
  }

  .navbar-vertical .container-fluid {
    display: block;
    padding: 0;
  }

  .navbar-vertical .navbar-brand {
    display: flex;
    justify-content: center;
    padding: 1.25rem 1rem;
  }

  /* Latar gelap : menutupi isi halaman sekaligus menjadi bidang tutup. */
  .laci-latar {
    position: fixed;
    inset: 0;
    z-index: 1040;
    background: rgba(15, 23, 42, .55);
    opacity: 0;
    transition: opacity .22s ease-out;
  }

  body.laci-buka .laci-latar { opacity: 1; }

  /* Halaman di belakang tidak ikut tergulir selama laci terbuka. */
  body.laci-buka { overflow: hidden; }

  /* Butir menu diberi bidang sentuh yang layak. */
  .navbar-vertical.navbar-light .navbar-nav .nav-link {
    min-height: 44px;
    display: flex;
    align-items: center;
  }

  /* Judul halaman di ponsel : dipendekkan daripada membungkus jadi dua
     baris dan mendorong menu pengguna keluar bilah.
     =================================================================
     min-width: 0 WAJIB ADA di pembungkusnya.

     .navbar-brand-title adalah butir flex, dan butir flex bawaannya
     min-width:auto — ia MENOLAK menyusut lebih kecil daripada isinya.
     Tanpa baris ini, judul tes yang panjang ("Hasil TOEFL Online Test
     by Bahasa Inggris Net #179 | Monday, 31 August 2026") melebar
     sampai 590px di layar 390px, dan SELURUH halaman jadi bisa digulir
     mendatar. Diukur di Chrome, bukan diperkirakan.

     text-overflow hanya bekerja kalau pemotongannya benar-benar terjadi
     di sini, jadi overflow:hidden dipasang pada pembungkusnya juga.
     ================================================================= */
  .navbar-brand-title {
    min-width: 0;
    overflow: hidden;
  }

  .navbar-brand-title .h3 {
    font-size: 1.05rem;
    display: block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* ---------------------------------------------------------------------
   Popup skor peserta (ponsel)
   ---------------------------------------------------------------------
   Isi popupnya sendiri tidak dibatasi media query : begitu terbuka ia
   harus tampil benar berapa pun lebar layarnya. Yang dibatasi hanya
   PENANDA di sel nama — di desktop kolom L/S/R sudah tampil sendiri, jadi
   namanya memang tidak perlu terlihat bisa disentuh.
   --------------------------------------------------------------------- */

@media (max-width: 767.98px) {
  .tabel-gulir tbody td.kolom-nama {
    position: relative;
    padding-right: 1.5rem;
    cursor: pointer;
  }

  /* Chevron menghadap KANAN : yang terbuka sebuah popup, bukan baris di
     bawahnya. Chevron ke bawah akan menjanjikan hal yang salah. */
  .tabel-gulir tbody td.kolom-nama::after {
    content: "";
    position: absolute;
    top: 50%;
    right: .55rem;
    width: .4rem;
    height: .4rem;
    margin-top: -.25rem;
    border-top: 2px solid #94a3b8;
    border-right: 2px solid #94a3b8;
    transform: rotate(45deg);
  }
}

.skor-popup {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

.skor-popup-baris {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .65rem .85rem;
  border: 1px solid var(--ui-garis);
  border-radius: .5rem;
  background: var(--ui-permukaan);
}

.skor-popup-label {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  min-width: 0;
}

/* Huruf L/S/R dibuat menonjol : itu yang tertulis di kepala kolom
   tabelnya, jadi hubungan antara popup dan tabel langsung terlihat. */
.skor-popup-huruf {
  font-size: 1rem;
  font-weight: 700;
  color: var(--ui-navy-2);
  flex: 0 0 auto;
}

.skor-popup-sesi {
  font-size: .8125rem;
  color: var(--ui-redup);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* tabular-nums : angka tidak bergeser lebarnya antar baris */
.skor-popup-nilai {
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--ui-aksen);
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
}

/* Total ditonjolkan : itu angka yang paling dicari. */
.skor-popup-total {
  border-color: transparent;
  background: var(--ui-navy);
}

.skor-popup-total .skor-popup-label {
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #94a3b8;
}

.skor-popup-total .skor-popup-nilai {
  font-size: 1.6rem;
  color: #ffffff;
}

/* Nama peserta bisa panjang; dibungkus daripada dipotong, karena inilah
   satu-satunya penanda popup ini milik siapa. */
.skor-popup-nama {
  overflow-wrap: anywhere;
  line-height: 1.35;
}

/* Tombol laci. Bidang sentuhnya 44px penuh walau ikonnya 24px. */
.btn-laci {
  width: 44px;
  height: 44px;
  margin-right: .5rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ui-navy-2);
  flex: 0 0 auto;
}

.btn-laci:hover,
.btn-laci:focus { background: rgba(15, 23, 42, .06); }

/* Menghormati pengguna yang mematikan animasi di sistemnya. */
@media (prefers-reduced-motion: reduce) {
  .navbar-vertical.navbar-light,
  .laci-latar { transition: none; }
}

/* ---------------------------------------------------------------------
   Kartu & modal
   --------------------------------------------------------------------- */

.card {
  border: 1px solid var(--ui-garis);
  border-radius: var(--ui-radius);
  box-shadow: var(--ui-bayang);
}

.card-header {
  border-bottom: 1px solid var(--ui-garis);
  background: transparent;
  padding-top: .9rem;
  padding-bottom: .9rem;
}

.card-title { font-weight: 600; }

.modal-content {
  border: 0;
  border-radius: var(--ui-radius);
  box-shadow: var(--ui-bayang-lg);
}

.modal-header,
.modal-footer { border-color: var(--ui-garis); }

/* Kartu angka dashboard */
.stat-card .stat-nilai { color: var(--ui-navy-2); }
.stat-card .stat-label { color: var(--ui-redup); }

.card-pintasan:hover {
  border-color: var(--ui-aksen);
  box-shadow: 0 4px 14px rgba(37, 99, 235, .14);
}

.kartu-pantau { border-left-width: 3px; }

/* ---------------------------------------------------------------------
   Form
   ---------------------------------------------------------------------

   form-floating memang ada di Tabler beta2 dan dipakai 51 kali di
   aplikasi ini, jadi yang dirapikan pola yang sudah dipakai — bukan
   diganti dengan pola lain yang harus disunting satu per satu.
   --------------------------------------------------------------------- */

.form-control,
.form-select {
  border-color: #cbd5e1;
  border-radius: .5rem;
  color: var(--ui-navy-2);
  transition: border-color .15s ease, box-shadow .15s ease;
}

.form-control:hover:not(:disabled):not([readonly]),
.form-select:hover:not(:disabled) { border-color: #94a3b8; }

/* Cincin fokus dibuat tebal dan berwarna aksen : ini penanda utama
   "kolom mana yang sedang saya isi" pada form panjang. */
.form-control:focus,
.form-select:focus {
  border-color: var(--ui-aksen);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, .15);
}

.form-control[readonly] {
  background-color: #f8fafc;
  color: var(--ui-redup);
}

.form-label {
  font-weight: 600;
  font-size: .8125rem;
  color: var(--ui-navy-2);
}

.form-hint { color: var(--ui-redup); }

.form-floating > label { color: var(--ui-redup); }

.form-check-input:checked {
  background-color: var(--ui-aksen);
  border-color: var(--ui-aksen);
}

.form-check-input:focus {
  border-color: var(--ui-aksen);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, .15);
}

.input-group-text {
  background: #f8fafc;
  border-color: #cbd5e1;
  color: var(--ui-redup);
}

/* ---------------------------------------------------------------------
   Tabel
   ---------------------------------------------------------------------
   Kepala tabel mengikuti pola yang dipakai aplikasi rujukan : huruf
   kecil berkapital dengan jarak antar huruf, di atas latar sangat muda.
   Lebar kolom nama dan sel aksi yang sudah diatur di atas TIDAK diubah.
   --------------------------------------------------------------------- */

/* Selektornya memakai kombinator anak, BUKAN ".table thead th".
   Tabler mewarnai setiap sel lewat `.table > :not(caption) > * > *`,
   dan ".table thead th" kekhususannya di bawah itu — aturannya akan
   tertulis rapi tapi tidak pernah terpakai.

   box-shadow ikut dinolkan karena Tabler tidak hanya memakai
   background-color: ia melapisi tiap sel dengan
   `inset 0 0 0 9999px var(--tblr-table-accent-bg)`. Selama accent-bg
   masih transparan lapisan itu tak terlihat, tapi begitu tabelnya
   memakai varian belang atau sorot, lapisan itu menutupi warna kepala
   yang kita pasang di sini. */
.table > thead > tr > th,
.tabel-gulir > thead > tr > th {
  background-color: #f8fafc;
  box-shadow: none;
  color: var(--ui-redup);
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  border-bottom: 1px solid var(--ui-garis);
}

.table tbody td {
  border-top-color: #eef2f7;
  vertical-align: middle;
}

/* Sel aksi yang menempel di kanan sudah punya aturan sorot sendiri di
   bagian tabel-gulir di atas, dengan warna yang sama. */
.table > tbody > tr:hover > td { background-color: #f8fafc; }

/* ---------------------------------------------------------------------
   Tombol & lencana
   --------------------------------------------------------------------- */

.btn { border-radius: .5rem; font-weight: 500; }

.btn-primary {
  background-color: var(--ui-aksen);
  border-color: var(--ui-aksen);
}

.btn-primary:hover,
.btn-primary:focus {
  background-color: var(--ui-aksen-2);
  border-color: var(--ui-aksen-2);
}

.btn-primary:focus,
.btn-outline-primary:focus { box-shadow: 0 0 0 3px rgba(37, 99, 235, .2); }

.btn-success { background-color: var(--ui-sukses); border-color: var(--ui-sukses); }
.btn-danger  { background-color: var(--ui-bahaya); border-color: var(--ui-bahaya); }

.badge {
  border-radius: .375rem;
  padding: .28em .6em;
  font-weight: 600;
}

/* Ikon aksi di kolom kanan : hanya radiusnya yang diselaraskan. Peta
   warnanya (kuning=salin, abu=detail, biru=buka, merah=hapus, ...)
   sengaja tidak disentuh — sudah dipakai dan dihafal. */
.btn-aksi { border-radius: .5rem; }

.page-item.active .page-link {
  background-color: var(--ui-aksen);
  border-color: var(--ui-aksen);
}

.alert { border-radius: .5rem; }

/* ---------------------------------------------------------------------
   Halaman masuk
   ---------------------------------------------------------------------
   Kelas .halaman-masuk dipasang di _partials/header-signin.php. Halaman
   ini tidak punya .wrapper maupun sidebar, jadi aturan tata letak di
   bagian atas berkas ini tidak mengenainya.
   --------------------------------------------------------------------- */

.halaman-masuk {
  background: var(--ui-latar);
  min-height: 100vh;
}

.halaman-masuk .card {
  border: 0;
  border-radius: 1rem;
  box-shadow: var(--ui-bayang-lg);
}

.halaman-masuk .card-body { padding: 2rem; }

.halaman-masuk .card-title {
  font-size: 1.35rem;
  font-weight: 700;
}

.sweet_loader {
	width: 140px;
	height: 140px;
	margin: 0 auto;
	animation-duration: 0.5s;
	animation-timing-function: linear;
	animation-iteration-count: infinite;
	animation-name: ro;
	transform-origin: 50% 50%;
	transform: rotate(0) translate(0,0);
}