/* ---------------------------------------------------------------------------
   Panel — satu-satunya berkas gaya.

   Ditulis tangan dan disajikan apa adanya: tidak ada build step, tidak ada
   npm, tidak ada berkas yang perlu di-generate saat deploy. Kalau suatu saat
   berkas ini terasa perlu dipecah, pecah jadi beberapa <link> — jangan
   masukkan bundler hanya untuk menggabungkannya kembali.

   Bahasa visualnya: skeuomorphism. Setiap benda di layar meniru benda fisik —
   panel terangkat dari permukaan, tombol punya tepi yang bisa ditekan, kotak
   isian tampak cekung ke dalam, dan bar kuota berupa alur berisi cairan.

   Semuanya dibuat dari gradien dan bayangan, tanpa satu pun berkas gambar:
   tekstur berbentuk gambar akan menambah permintaan HTTP dan berkas biner ke
   repositori yang sengaja bebas build step.

   Aturan yang tidak boleh dilanggar sambil mengejar tampilan ini:
   kontras teks dan penanda fokus keyboard tidak boleh dikorbankan demi kilau.
   --------------------------------------------------------------------------- */

:root {
  /* Tema tunggal, gelap. Disetel eksplisit supaya kontrol bawaan peramban —
     kotak centang, penggulir, kotak berkas — ikut digambar versi gelapnya.
     Tanpa ini semuanya muncul putih terang di tengah panel navy. */
  color-scheme: dark;

  /*
   | Navy pekat hanya dipakai untuk BIDANG halaman. Permukaan yang membawa
   | teks — panel, bilah kepala, tabel — memakai abu batu tua berkadar warna
   | rendah.
   |
   | Alasannya: kalau semuanya navy dengan kejenuhan yang sama, tiap lapisan
   | hanya berbeda tipis dalam kecerahan, dan seluruh halaman melebur jadi satu
   | blok berat. Dengan menurunkan kadar warna permukaan, navy yang tersisa —
   | latar, tombol utama, tautan — justru terbaca sebagai aksen.
   |
   | Jarak kecerahan antar lapisan juga dilebarkan supaya urutan tumpukannya
   | terbaca: latar paling gelap, panel naik jelas, bilah kepala naik lagi.
   */
  --bg:            #0b1220;
  --bg-2:          #070b14;
  --surface:       #222b39;
  --surface-hi:    #2d3849;
  --surface-2:     #1c2431;
  --head:          #2e3949;
  --head-2:        #26303e;
  --sunk:          #1a212c;

  /* Kotak isian dibuat LEBIH TERANG dari panel, bukan lebih gelap.
     Di tema gelap, bidang yang lebih terang justru terbaca sebagai "bisa
     diisi" — sedangkan cekungan yang lebih gelap gampang tertukar dengan
     sela antar panel. Kedalamannya tetap datang dari bayangan dalam. */
  --field:         #353f4e;
  --border:        #10161f;
  --border-soft:   #333e4e;

  --text:          #e8ecf2;
  --text-muted:    #9ba6b6;

  --link:          #7fb0f2;

  --primary:       #2f5d9e;
  --primary-2:     #21456f;
  --primary-text:  #ffffff;

  --ok:            #86d3a5;
  --ok-bg:         #22392e;
  --ok-bg-2:       #1b2e25;
  --ok-border:     #3f6650;

  --warn:          #e8bf83;
  --warn-bg:       #3a3325;
  --warn-bg-2:     #2e291d;
  --warn-border:   #6b5b39;

  --danger:        #ef9d95;
  --danger-bg:     #3e2724;
  --danger-bg-hi:  #4d3230;
  --danger-bg-2:   #32201d;
  --danger-border: #6d4340;

  --info-bg:       #223145;
  --info-border:   #36485f;

  /* Bahan dasar timbul-tenggelam. Semua efek kedalaman memakai keempat nilai
     ini supaya arah cahayanya konsisten: sumbernya selalu dari atas. */
  /* Bayangannya dilembutkan: dengan jarak kecerahan antar lapisan yang sudah
     lebar, bayangan pekat hanya menambah bobot tanpa menambah kejelasan. */
  --bevel-top:     rgba(255, 255, 255, .09);
  --bevel-bottom:  rgba(0, 0, 0, .40);
  --lift:          0 1px 1px rgba(0, 0, 0, .25), 0 2px 8px rgba(0, 0, 0, .22);
  --lift-strong:   0 1px 2px rgba(0, 0, 0, .32), 0 4px 12px rgba(0, 0, 0, .28);
  --groove:        inset 0 1px 3px rgba(0, 0, 0, .38), inset 0 -1px 0 rgba(255, 255, 255, .05);

  --radius: 5px;
  --radius-lg: 7px;

  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
}

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

* { box-sizing: border-box; }

/* Tekstur kain: dua gradien miring beralpha rendah, bukan berkas gambar. */
body {
  margin: 0;
  background-color: var(--bg);
  background-image:
    repeating-linear-gradient(45deg,  rgba(255, 255, 255, .022) 0 2px, transparent 2px 4px),
    repeating-linear-gradient(-45deg, rgba(0, 0, 0, .10) 0 2px, transparent 2px 4px),
    linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%);
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.55;
  -webkit-text-size-adjust: 100%;
}

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

p { margin: 0 0 .75rem; }
p:last-child { margin-bottom: 0; }

ul { margin: 0 0 .75rem; padding-left: 1.25rem; }
ul:last-child { margin-bottom: 0; }
li { margin-bottom: .25rem; }

code, .mono { font-family: var(--mono); font-size: .9285em; }

code {
  background: var(--sunk);
  border: 1px solid var(--border-soft);
  border-radius: 3px;
  padding: .05em .3em;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, .40);
}

.muted { color: var(--text-muted); }
.small { font-size: .8571rem; }

/* font-weight disetel eksplisit: elemen ini sering bersarang di dalam <label>
   yang tebal, dan tanpa ini keterangan bantuannya ikut menebal. */
small, .help {
  display: block;
  color: var(--text-muted);
  font-size: .8571rem;
  font-weight: 400;
  line-height: 1.5;
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

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

.page {
  max-width: 60rem;
  margin: 0 auto;
  padding: 1rem 1rem 3rem;
}

/* Kepala halaman: nama panel + siapa yang sedang masuk. Sengaja satu kotak
   sendiri, bukan bilah melebar, supaya sejajar dengan kolom di bawahnya. */
.masthead {
  background-image: linear-gradient(180deg, var(--surface) 0%, var(--surface-2) 100%);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: inset 0 1px 0 var(--bevel-top), var(--lift);
  padding: .875rem 1rem;
  margin-bottom: 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.masthead-title {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: 1.125rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--text);
  text-decoration: none;
  text-shadow: 0 1px 0 var(--bevel-top);
}

/* Ikon Phosphor dari sprite. Ukurannya dalam em supaya ikut besar teks di
   sekitarnya, dan warnanya currentColor supaya ikut warna teks — termasuk
   merah di zona berbahaya, tanpa aturan tambahan. */
.icon {
  width: 1.05em;
  height: 1.05em;
  flex: none;
  fill: currentColor;
  vertical-align: -.15em;
}

/* Petir memakai warna aksen supaya jadi satu-satunya titik berwarna di bilah
   atas — cukup untuk menandai merek tanpa menarik perhatian dari isi halaman. */
.masthead-title .icon {
  width: 1.15em;
  height: 1.15em;
  color: var(--link);
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .45));
}

/* Ikon di dalam label kolom tabel kunci–nilai: diredupkan supaya angkanya
   yang tetap jadi hal pertama yang terbaca. */
.statlist th .icon,
.kv th .icon {
  color: var(--text-muted);
  margin-right: .4em;
}

.masthead-left {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  min-width: 0;
}

.masthead-sep { color: var(--border-soft); }

/* Email dibiarkan memendek sendiri saat sempit — memaksanya utuh akan
   mendorong tombol keluar keluar dari layar. */
.masthead-user {
  font-size: .8571rem;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.masthead-right { display: flex; align-items: center; gap: .625rem; font-size: .8571rem; }

/* Tanpa garis bawah: ini menu, bukan tautan di dalam kalimat. Garis bawah
   berguna untuk menandai tautan yang menyelip di antara teks — di deretan
   menu ia hanya menambah coretan. Petunjuk bahwa ini bisa diklik sudah
   datang dari posisinya, ikonnya, dan perubahan warna saat disentuh. */
.masthead-right a {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  text-decoration: none;
}

.masthead-right a:hover { color: var(--text); }

.page-narrow { max-width: 40rem; }

/* Lebih sempit lagi, khusus halaman masuk dan daftar. Keduanya berdiri
   sendiri tanpa kepala halaman, dan kartu selebar formulir isi panel justru
   membuatnya terasa mengambang di tengah layar kosong. */
.page-tight { max-width: 27rem; }

/* Halaman tanpa kepala: isinya ditengahkan tegak lurus di layar. */
.page-center {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* Atribut hidden harus mengalahkan aturan display mana pun di atasnya —
   tanpa ini, elemen ber-display:flex tetap tampil walau di-hidden. */
[hidden] { display: none !important; }

/* ------------------------------------------------------------------- Panel */

/* Panel terangkat dari permukaan: garis terang di tepi atas dalam, bayangan
   jatuh di luar. Keduanya perlu — hanya bayangan saja terbaca sebagai kartu
   datar yang melayang, bukan benda yang punya ketebalan. */
.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: inset 0 1px 0 var(--bevel-top), var(--lift);
  margin-bottom: 1rem;
}

.panel:last-child { margin-bottom: 0; }

.panel-head {
  background-image: linear-gradient(180deg, var(--head) 0%, var(--head-2) 100%);
  border-bottom: 1px solid var(--border);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: inset 0 1px 0 var(--bevel-top);
  padding: .5rem .875rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
}

.panel-title {
  font-size: .9285rem;
  font-weight: 700;
  text-shadow: 0 1px 0 var(--bevel-top);
}

.panel-body { padding: .875rem; }
.panel-body > :last-child { margin-bottom: 0; }

.panel-body.flush { padding: 0; }

/* ------------------------------------------------------------------- Flash */

.flash {
  display: flex;
  gap: .5rem;
  padding: .625rem .75rem;
  border: 1px solid;
  border-radius: var(--radius);
  box-shadow: inset 0 1px 0 var(--bevel-top), var(--lift);
  margin-bottom: 1rem;
}

.flash-icon { flex: none; font-weight: 700; text-shadow: 0 1px 0 var(--bevel-top); }

.flash-ok {
  background-image: linear-gradient(180deg, var(--ok-bg) 0%, var(--ok-bg-2) 100%);
  border-color: var(--ok-border);
  color: var(--ok);
}

.flash-err {
  background-image: linear-gradient(180deg, var(--danger-bg) 0%, var(--danger-bg-2) 100%);
  border-color: var(--danger-border);
  color: var(--danger);
}

.flash-body { color: var(--text); }
.flash ul { margin: .25rem 0 0; }

/* ------------------------------------------------------------------ Tombol */

/* Tombol yang bisa ditekan: kilau di separuh atas, tepi bawah lebih gelap,
   dan saat ditekan bayangannya berbalik ke dalam sambil turun satu piksel. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .35rem;
  font: inherit;
  font-size: .8571rem;
  font-weight: 600;
  line-height: 1.3;
  padding: .4375rem .8125rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background-image: linear-gradient(180deg, var(--surface) 0%, var(--surface-2) 50%, var(--head) 100%);
  box-shadow: inset 0 1px 0 var(--bevel-top), var(--lift);
  color: var(--text);
  text-shadow: 0 1px 0 var(--bevel-top);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
}

.btn:hover { background-image: linear-gradient(180deg, var(--surface-hi) 0%, var(--surface) 55%, var(--head) 100%); }

.btn:active {
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, .28);
  transform: translateY(1px);
}

/* Penanda fokus keyboard tidak ikut dihaluskan: ia harus tetap menonjol di
   atas semua kilau, karena hanya itu yang dipunyai orang tanpa tetikus. */
.btn:focus-visible,
.input:focus-visible,
a:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 2px;
}

/* Satu tombol utama per panel: yang paling mungkin ditekan orang. */
.btn-primary {
  background-image: linear-gradient(180deg, var(--primary) 0%, var(--primary-2) 100%);
  border-color: var(--primary-2);
  color: var(--primary-text);
  text-shadow: 0 -1px 0 rgba(0, 0, 0, .45);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .22), var(--lift-strong);
}

.btn-primary:hover {
  background-image: linear-gradient(180deg, color-mix(in srgb, var(--primary) 85%, white) 0%, var(--primary-2) 100%);
}

/* Merah hanya untuk yang tidak bisa dibatalkan. Kalau semua tombol berisiko
   diberi warna ini, warnanya berhenti berarti apa-apa. */
.btn-danger {
  background-image: linear-gradient(180deg, var(--danger-bg) 0%, var(--danger-bg-2) 100%);
  border-color: var(--danger-border);
  color: var(--danger);
}

.btn-danger:hover {
  background-image: linear-gradient(180deg, var(--danger-bg-hi) 0%, var(--danger-bg-2) 100%);
}

.btn-sm { padding: .25rem .5625rem; font-size: .8125rem; }

.btn-row { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }

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

.field { margin-bottom: .875rem; }

.field > label,
.label {
  display: block;
  font-weight: 700;
  margin-bottom: .25rem;
  text-shadow: 0 1px 0 var(--bevel-top);
}

/* Kotak isian tampak cekung: bayangan masuk dari atas, garis terang tipis di
   bibir bawah. Kebalikan persis dari tombol, supaya sekali lihat ketahuan
   mana yang ditekan dan mana yang diisi. */
.input {
  font: inherit;
  width: 100%;
  padding: .4375rem .5rem;
  background: var(--field);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--groove);
}

.input:focus {
  border-color: var(--link);
  box-shadow: var(--groove), 0 0 0 3px color-mix(in srgb, var(--link) 25%, transparent);
  outline: none;
}

.input[readonly] { background: var(--sunk); }

/* Disetel eksplisit, bukan dibiarkan ke bawaan peramban: di atas latar isian
   yang lebih terang, warna redup biasa (--text-muted) hanya mencapai 4.32:1 —
   sedikit di bawah ambang. */
.input::placeholder { color: #a4aebd; opacity: 1; }

textarea.input { font-family: var(--mono); font-size: .8571rem; line-height: 1.5; }

.input-sm { padding: .25rem .4375rem; font-size: .8125rem; }

/* Subdomain diketik tepat di sebelah sufiks domain yang tidak bisa diubah.
   Menyatukannya dalam satu kotak membuat orang langsung melihat bahwa yang
   dia ketik dan sufiksnya adalah satu alamat utuh. */
.input-suffix {
  display: flex;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--field);
  box-shadow: var(--groove);
  overflow: hidden;
}

.input-suffix:focus-within {
  border-color: var(--link);
  box-shadow: var(--groove), 0 0 0 3px color-mix(in srgb, var(--link) 25%, transparent);
}

.input-suffix .input {
  border: 0;
  border-radius: 0;
  flex: 1 1 auto;
  min-width: 0;
  box-shadow: none;
  background: transparent;
}

.input-suffix .input:focus { box-shadow: none; }
.input-suffix .input:focus-visible { outline: none; }

/* Sufiks dibuat terangkat, seperti pelat logam yang ditempel di ujung alur. */
.input-suffix .suffix {
  display: flex;
  align-items: center;
  padding: 0 .5rem;
  background-image: linear-gradient(180deg, var(--head) 0%, var(--head-2) 100%);
  border-left: 1px solid var(--border);
  box-shadow: inset 0 1px 0 var(--bevel-top);
  color: var(--text-muted);
  font-family: var(--mono);
  font-size: .8571rem;
  white-space: nowrap;
}

/* Ditulis dengan `.field > label.check` supaya spesifisitasnya menyamai aturan
   `.field > label` di atas. Tanpa itu label kotak centang ikut jadi block dan
   tebal, kotaknya terlempar ke baris sendiri, dan teks bantuannya ikut menebal. */
.check,
.field > label.check {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  font-weight: 400;
  margin-bottom: 0;
}

.check input { margin: .25rem 0 0; flex: none; }
.check .label { margin-bottom: 0; }

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 0 1rem;
}

/* Tepat dua kolom, bukan auto-fit.
   auto-fit memilih jumlah kolom sendiri berdasarkan lebar layar, jadi empat
   isian bisa jatuh jadi tiga kolom + satu yatim di bawahnya. Kalau isiannya
   memang berpasangan, jumlah kolomnya harus ditentukan, bukan ditebak. */
.form-grid-2 {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 1rem;
}

@media (max-width: 34rem) {
  .form-grid-2 { grid-template-columns: 1fr; }
}

.form-section-title {
  font-size: .8125rem;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: .625rem;
}

/* Garis pemisah dibuat dua baris — gelap lalu terang — supaya terbaca sebagai
   torehan pada permukaan, bukan sekadar garis yang digambar di atasnya. */
.form-foot {
  border-top: 1px solid var(--border-soft);
  box-shadow: inset 0 1px 0 var(--bevel-top);
  margin-top: .875rem;
  padding-top: .75rem;
}

/* ---------------------------------------------------------------- Dropzone */

/* Seluruh kotak adalah <label>: tidak ada tombol di dalamnya, bidangnya
   sendiri yang jadi sasaran klik. Dibuat cekung — sebuah wadah yang menunggu
   diisi, bukan tombol yang menunggu ditekan. */
.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .25rem;
  border: 2px dashed var(--border);
  border-radius: var(--radius-lg);
  background-image: linear-gradient(180deg, var(--sunk) 0%, var(--surface-2) 100%);
  box-shadow: var(--groove);
  padding: 2.25rem 1rem;
  text-align: center;
  margin-bottom: .875rem;
  cursor: pointer;
}

.dropzone:hover { border-color: var(--text-muted); }

/* Input-nya tak terlihat, jadi tanda fokus keyboard harus dipinjamkan ke
   kotaknya — kalau tidak, orang yang menekan Tab tidak tahu ia ada di sini. */
.dropzone:focus-within {
  border-color: var(--link);
  outline: 2px solid var(--link);
  outline-offset: 2px;
}

.dropzone.is-dragging {
  border-color: var(--link);
  background-image: linear-gradient(180deg, var(--info-bg) 0%, var(--surface-2) 100%);
}

/* font-weight ringan supaya tanda tambahnya terbaca sebagai ikon, bukan huruf. */
.dropzone-plus {
  font-size: 2.25rem;
  font-weight: 200;
  line-height: 1;
  color: var(--text-muted);
  text-shadow: 0 1px 0 var(--bevel-top);
}

.dropzone:hover .dropzone-plus,
.dropzone.is-dragging .dropzone-plus { color: var(--link); }

.dropzone-hint { font-size: .8571rem; color: var(--text-muted); }

/* Tombol kirim mati sampai ada berkas yang dipilih — hanya berlaku saat
   JavaScript hidup; tanpanya kotak isian berkas biasa yang dipakai.
   Kilaunya ikut dimatikan supaya matinya terbaca, bukan cuma pudar. */
.btn[disabled] {
  opacity: .55;
  cursor: not-allowed;
  background-image: none;
  background-color: var(--head-2);
  box-shadow: none;
  text-shadow: none;
}

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

/* Tabel dengan 5–6 kolom tidak akan pernah muat di layar ponsel. Menggulir
   tabelnya sendiri lebih jujur daripada memaksa kolom menyempit sampai
   isinya tidak terbaca lagi. */
.table-wrap { overflow-x: auto; }

.table { width: 100%; border-collapse: collapse; }

.table th,
.table td {
  text-align: left;
  padding: .5rem .875rem;
  border-bottom: 1px solid var(--border-soft);
  vertical-align: middle;
}

.table thead th {
  background-image: linear-gradient(180deg, var(--head) 0%, var(--head-2) 100%);
  border-bottom: 1px solid var(--border);
  box-shadow: inset 0 1px 0 var(--bevel-top);
  font-size: .8125rem;
  font-weight: 700;
  color: var(--text-muted);
  text-shadow: 0 1px 0 var(--bevel-top);
  white-space: nowrap;
}

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

.table .num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.table .nowrap { white-space: nowrap; }
.table .empty { color: var(--text-muted); text-align: center; padding: 1.5rem; }

/* Tabel kunci–nilai untuk halaman rincian. Bukan data berbaris, jadi tanpa
   kepala kolom. */
.kv { width: 100%; border-collapse: collapse; }

.kv th {
  text-align: left;
  font-weight: 400;
  color: var(--text-muted);
  padding: .3125rem 1rem .3125rem 0;
  white-space: nowrap;
  vertical-align: top;
  width: 1%;
}

.kv td { padding: .3125rem 0; vertical-align: top; }

/* ------------------------------------------------------------------- Meter */

/* Alur yang dicetak ke dalam permukaan, diisi cairan mengkilap. */
.meter {
  height: 14px;
  background-image: linear-gradient(180deg, var(--sunk) 0%, var(--surface-2) 100%);
  border: 1px solid var(--border);
  border-radius: 999px;
  box-shadow: var(--groove);
  overflow: hidden;
}

.meter > span {
  display: block;
  height: 100%;
  border-radius: 999px;
  background-color: var(--ok);
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .30) 0%, rgba(255, 255, 255, .08) 48%, rgba(0, 0, 0, .18) 52%, rgba(0, 0, 0, .10) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25);
}

/* Kuota hampir habis diberi warna sendiri: angka persen saja mudah terlewat,
   dan upload yang ditolak karena kuota adalah keluhan yang paling sering. */
.meter.is-high > span { background-color: var(--warn); }
.meter.is-full > span { background-color: var(--danger); }

.meter-label {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  font-size: .8571rem;
  margin-bottom: .25rem;
}

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

.badge {
  display: inline-block;
  padding: .0625rem .5rem;
  border: 1px solid;
  border-radius: 999px;
  font-size: .8125rem;
  font-weight: 600;
  white-space: nowrap;
  box-shadow: inset 0 1px 0 var(--bevel-top), 0 1px 1px rgba(0, 0, 0, .35);
  text-shadow: 0 1px 0 rgba(0, 0, 0, .45);
}

.badge-ok {
  background-image: linear-gradient(180deg, var(--ok-bg) 0%, var(--ok-bg-2) 100%);
  border-color: var(--ok-border);
  color: var(--ok);
}

.badge-warn {
  background-image: linear-gradient(180deg, var(--warn-bg) 0%, var(--warn-bg-2) 100%);
  border-color: var(--warn-border);
  color: var(--warn);
}

.badge-off {
  background-image: linear-gradient(180deg, var(--surface-2) 0%, var(--head-2) 100%);
  border-color: var(--border);
  color: var(--text-muted);
}

/* -------------------------------------------------------------------- Stat */

.statlist { width: 100%; border-collapse: collapse; }

.statlist th,
.statlist td {
  padding: .375rem .875rem;
  border-bottom: 1px solid var(--border-soft);
  font-size: .8571rem;
}

.statlist tr:last-child th,
.statlist tr:last-child td { border-bottom: 0; }

.statlist th { text-align: left; font-weight: 400; color: var(--text-muted); }
.statlist td { text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------------- Pagination */

.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: .625rem;
  border-top: 1px solid var(--border-soft);
  box-shadow: inset 0 1px 0 var(--bevel-top);
  font-size: .8571rem;
  color: var(--text-muted);
}

/* ------------------------------------------------------- Halaman selesai */

.done { text-align: center; padding: 2rem 1.25rem; }

/* Manik timbul: gradien radial dengan titik terang di kiri-atas, meniru
   pantulan cahaya pada permukaan cembung. */
.done-mark {
  width: 4rem;
  height: 4rem;
  margin: 0 auto 1rem;
  border-radius: 50%;
  background-color: var(--ok-bg);
  background-image: radial-gradient(circle at 35% 28%, rgba(255, 255, 255, .22) 0%, var(--ok-bg) 45%, var(--ok-bg-2) 100%);
  border: 1px solid var(--ok-border);
  box-shadow: inset 0 1px 0 var(--bevel-top), var(--lift);
  color: var(--ok);
  animation: done-pop .42s cubic-bezier(.2, .9, .3, 1.35) both;
}

.done-check { display: block; width: 100%; height: 100%; }

/* Panjang garis centang dipatok 60 — sedikit di atas panjang path sebenarnya,
   supaya goresannya benar-benar mulai dari kosong. */
.done-check-mark {
  fill: none;
  stroke: var(--ok);
  stroke-width: 5;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 60;
  stroke-dashoffset: 60;
  animation: done-draw .4s .22s ease-out forwards;
}

@keyframes done-pop {
  from { transform: scale(.4); opacity: 0; }
  to   { transform: scale(1);  opacity: 1; }
}

@keyframes done-draw {
  to { stroke-dashoffset: 0; }
}

.done-title { font-size: 1.25rem; margin: 0 0 .5rem; text-shadow: 0 1px 0 var(--bevel-top); }
.done-url { font-size: 1rem; }
.done-actions { justify-content: center; margin-top: 1rem; }

/* ------------------------------------------------------------------ Urut */

/* Kepala kolom yang bisa diklik. Warnanya tetap sama dengan kepala kolom
   biasa supaya barisnya tidak berubah jadi deretan tautan biru. */
.sort {
  color: inherit;
  text-decoration: none;
  white-space: nowrap;
}

.sort:hover { color: var(--text); text-decoration: underline; }
.sort.is-active { color: var(--text); }
.sort-mark { margin-left: .2em; }

.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
  border-top: 1px solid var(--border-soft);
  box-shadow: inset 0 1px 0 var(--bevel-top);
}

/* Baris filter status. Dibuat datar, bukan bertumpuk seperti tombol, supaya
   tidak bersaing dengan aksi sungguhan di tabel di bawahnya. */
.filters {
  display: flex;
  align-items: center;
  gap: .375rem;
  flex-wrap: wrap;
  padding-top: 0;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .2rem .55rem;
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  font-size: .8125rem;
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
}

.chip:hover { border-color: var(--text-muted); color: var(--text); }

.chip.is-active {
  background-image: linear-gradient(180deg, var(--primary) 0%, var(--primary-2) 100%);
  border-color: var(--primary-2);
  color: var(--primary-text);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .18);
}

/* -------------------------------------------------------------- Pohon berkas */

.tree-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
  border-top: 1px solid var(--border-soft);
  box-shadow: inset 0 1px 0 var(--bevel-top);
}

.tree {
  background-image: linear-gradient(180deg, var(--sunk) 0%, var(--surface-2) 100%);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--groove);
  padding: .375rem;
  font-size: .875rem;
}

.tree-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .25rem .4375rem;
  border-radius: 3px;
}

.tree-row:hover { background: rgba(255, 255, 255, .04); }

summary.tree-row {
  list-style: none;
  cursor: pointer;
  user-select: none;
}

summary.tree-row::-webkit-details-marker { display: none; }

.tree-name {
  display: flex;
  align-items: center;
  gap: .4rem;
  min-width: 0;
  font-family: var(--mono);
  font-size: .8571rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Berkas dimundurkan sejauh lebar panah supaya namanya sejajar dengan nama
   folder di atasnya, bukan dengan panahnya. */
.tree-leaf { padding-left: 1.45em; }

.tree-caret {
  display: inline-flex;
  flex: none;
  color: var(--text-muted);
  transform: rotate(-90deg);
  transition: transform .12s ease;
}

details[open] > summary .tree-caret { transform: rotate(0deg); }

.tree-meta {
  flex: none;
  font-family: var(--sans);
  font-size: .8125rem;
  color: var(--text-muted);
}

.tree-size {
  flex: none;
  font-size: .8125rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* Garis penuntun kedalaman. Tanpa ini, folder bersarang tiga tingkat hanya
   terbaca sebagai deretan yang menjorok tanpa batas yang jelas. */
.tree-branch {
  margin-left: .75rem;
  padding-left: .5rem;
  border-left: 1px solid var(--border-soft);
}

.tree-more { color: var(--text-muted); font-size: .8125rem; padding-left: 1.85em; }

@media (prefers-reduced-motion: reduce) {
  .tree-caret { transition: none; }
}

/* ------------------------------------------------------- Zona berbahaya */

.panel-danger { border-color: var(--danger-border); }

.panel-danger > details > summary.panel-head,
.panel-danger .panel-head {
  background-image: linear-gradient(180deg, var(--danger-bg) 0%, var(--danger-bg-2) 100%);
  border-color: var(--danger-border);
}

.panel-danger .panel-title { color: var(--danger); }

/* Satu aksi per baris: keterangannya di kiri, kontrolnya di kanan. Menaruh
   beberapa tombol berdampingan tanpa label membuat orang harus menebak mana
   yang menghapus apa. */
.action-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .75rem .875rem;
  border-bottom: 1px solid var(--border-soft);
}

.action-row:last-child { border-bottom: 0; }
.action-row > div { min-width: 12rem; }

/* ------------------------------------------------------------ Serba-serbi */

.center { text-align: center; }

.btn-block { width: 100%; }

.input-lg .input { font-size: 1.0625rem; padding: .625rem .75rem; }
.input-lg .suffix { font-size: .9375rem; }

/* Panel yang bisa dilipat: bilah judulnya sekaligus jadi tombolnya, supaya
   hal yang jarang dipakai tidak ikut memenuhi layar setiap saat. */
details > summary.panel-head {
  list-style: none;
  cursor: pointer;
  user-select: none;
  border-bottom: 0;
  border-radius: var(--radius-lg);
}

details[open] > summary.panel-head {
  border-bottom: 1px solid var(--border);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

details > summary.panel-head::-webkit-details-marker { display: none; }

/* Panahnya ikon di dalam markup, bukan ::after berisi karakter. Karakter
   seperti ⌄ punya tinggi dan garis dasar yang berbeda-beda antar fon, jadi
   letaknya tidak pernah benar-benar pas; ikon SVG diratakan flex seperti
   elemen lain. */
.panel-caret {
  display: inline-flex;
  color: var(--text-muted);
  transition: transform .15s ease;
}

details[open] > summary.panel-head .panel-caret { transform: rotate(180deg); }

/* ------------------------------------------------------------- Kubus Rubik */

/* Hiasan halaman masuk. Ruang 3D-nya dibangun dari satu titik pusat: .cube
   sendiri tidak punya ukuran, dan ke-26 kubus kecil digeser dari titik itu.
   Dengan begitu sumbu putarnya jatuh tepat di tengah kubus tanpa perlu
   menghitung transform-origin sama sekali. */
.cube-stage {
  --cubie: 3.25rem;
  display: grid;
  place-items: center;
  min-height: 21rem;
  perspective: 52rem;
}

.cube {
  position: relative;
  transform-style: preserve-3d;
  animation: cube-tumble 30s linear infinite;
}

/* Lapisan atas berputar seperempat demi seperempat. Empat kali seperempat
   putaran mengembalikannya persis ke tempat semula, jadi gerakannya bisa
   diulang selamanya tanpa pernah terlihat melompat balik. */
.cube-layer {
  position: absolute;
  transform-style: preserve-3d;
  animation: cube-turn 14s ease-in-out infinite;
}

.cubie {
  position: absolute;
  width: var(--cubie);
  height: var(--cubie);
  margin: calc(var(--cubie) / -2);
  transform-style: preserve-3d;
  transform: translate3d(
    calc(var(--x) * var(--cubie)),
    calc(var(--y) * var(--cubie)),
    calc(var(--z) * var(--cubie))
  );
}

.cubie-face {
  position: absolute;
  inset: 0;
  border-radius: .3rem;
  background: #0b111b;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .6);
}

.face-f { transform: translateZ(calc(var(--cubie) / 2)); }
.face-b { transform: rotateY(180deg) translateZ(calc(var(--cubie) / 2)); }
.face-r { transform: rotateY(90deg) translateZ(calc(var(--cubie) / 2)); }
.face-l { transform: rotateY(-90deg) translateZ(calc(var(--cubie) / 2)); }
.face-u { transform: rotateX(90deg) translateZ(calc(var(--cubie) / 2)); }
.face-d { transform: rotateX(-90deg) translateZ(calc(var(--cubie) / 2)); }

/* Bingkai gelapnya dibuat dari border, bukan dari kotak lain di dalamnya:
   stiker aslinya memang lebih kecil dari permukaan kubus, dan tanpa sela itu
   sembilan stiker sewarna melebur jadi satu bidang polos. */
.sticker {
  border: .16rem solid #080d15;
  box-shadow:
    inset 0 0 0 1px rgba(0, 0, 0, .5),
    inset 0 .14rem .3rem rgba(255, 255, 255, .22);
}

/* Warna baku Rubik, diturunkan sedikit kepekatannya supaya tidak menyala di
   atas latar gelap panel. */
.sticker-u { background: #dfe6f0; }
.sticker-d { background: #d8bc4c; }
.sticker-f { background: #3d9760; }
.sticker-b { background: #3a6cbe; }
.sticker-r { background: #bc4a4a; }
.sticker-l { background: #cc8038; }

@keyframes cube-tumble {
  from { transform: rotateX(-24deg) rotateY(-32deg); }
  to   { transform: rotateX(-24deg) rotateY(328deg); }
}

@keyframes cube-turn {
  0%,   16% { transform: rotateY(0deg); }
  25%,  41% { transform: rotateY(90deg); }
  50%,  66% { transform: rotateY(180deg); }
  75%,  91% { transform: rotateY(270deg); }
  100%      { transform: rotateY(360deg); }
}

/* Pergantian kubus dan formulir saat Ctrl+. ditekan. */
#cube:not([hidden]),
#secret:not([hidden]) { animation: swap-in .3s ease-out; }

@keyframes swap-in {
  from { opacity: 0; transform: scale(.96); }
  to   { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------------ Ponsel */

@media (max-width: 40rem) {
  .page { padding: .75rem .75rem 2rem; }
  .masthead { padding: .75rem; }
  .masthead-title { font-size: 1.125rem; }

  .cube-stage {
    --cubie: 2rem;
    min-height: 14rem;
  }
}

/* Sebagian orang mematikan animasi karena gerakan membuatnya pusing. Tombol
   yang turun saat ditekan termasuk gerakan.
   Centang di halaman selesai langsung ditampilkan utuh — kalau animasinya
   hanya dimatikan tanpa menyetel keadaan akhirnya, garisnya tidak akan pernah
   tergambar dan manik itu tampak kosong. */
@media (prefers-reduced-motion: reduce) {
  .btn:active { transform: none; }

  .done-mark { animation: none; }

  .done-check-mark {
    animation: none;
    stroke-dashoffset: 0;
  }

  .panel-caret { transition: none; }

  /* Kubusnya tetap ditampilkan, hanya berhenti berputar: yang mengganggu itu
     gerakannya, bukan gambarnya. Sudutnya disetel supaya tiga sisi tetap
     terlihat — tanpa itu ia berhenti menghadap lurus ke depan dan terbaca
     sebagai kotak datar, bukan kubus. */
  .cube { animation: none; transform: rotateX(-24deg) rotateY(-32deg); }

  .cube-layer { animation: none; }

  #cube:not([hidden]),
  #secret:not([hidden]) { animation: none; }
}
