/* =====================================================================
   KUBICSA — components.css
   Tombol, kartu, panggung, tangga titik, modal, toast, stiker.
   ===================================================================== */

/* ---------------------------------------------------------------------
   1. Tombol
   ---------------------------------------------------------------------
   Gaya tombol fisik: bayangan PADAT tanpa blur, dan saat ditekan tombol
   turun sementara bayangannya mengecil (§10.6). Bayangan blur ala
   korporat merusak nuansa stiker yang diminta §10.1.

   Label memakai --tinta, bukan putih. Putih di atas --primer hanya
   mencapai 2,60:1 (manis) dan 2,09:1 (sejuk) — jauh di bawah WCAG AA,
   padahal ini elemen yang paling sering disentuh.
   --------------------------------------------------------------------- */
.tombol {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);

  min-height: var(--sentuh);     /* target sentuh 44px (§10.8) */
  min-width: var(--sentuh);
  padding: 12px 24px;

  font-family: var(--font-teks);
  font-size: var(--f-subjudul);
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;

  border-radius: var(--radius-pil);
  transition: transform 120ms ease, box-shadow 120ms ease, opacity 150ms ease;
  user-select: none;
  touch-action: manipulation;    /* buang jeda 300ms di ponsel */
}

.tombol:active:not(:disabled) {
  transform: translateY(3px);
  box-shadow: 0 1px 0 var(--bayang-tombol, var(--primer-tua));
}

.tombol:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
}

.tombol-utama {
  background: var(--primer);
  color: var(--tinta);
  box-shadow: 0 var(--angkat) 0 var(--primer-tua);
  --bayang-tombol: var(--primer-tua);
}

.tombol-kedua {
  background: var(--panggung);
  color: var(--primer-tua);
  border: var(--tebal-stiker) solid var(--primer);
  box-shadow: 0 var(--angkat) 0 var(--primer);
  --bayang-tombol: var(--primer);
}

.tombol-aksen {
  background: var(--aksen);
  color: var(--tinta);
  box-shadow: 0 var(--angkat) 0 #C9A62E;
  --bayang-tombol: #C9A62E;
}

/* Tombol kunci jawaban: melekat di bawah layar, selalu terjangkau ibu jari. */
.tombol-sticky {
  position: sticky;
  bottom: var(--sp-3);
  width: 100%;
  z-index: 3;
}

/* ---------------------------------------------------------------------
   2. Panggung — aturan paling penting (§10.3)
   ---------------------------------------------------------------------
   Objek 3D TIDAK BOLEH diletakkan di atas latar berpola atau bergradasi.
   Kontras rendah membuat siswa salah bukan karena kemampuan spasialnya,
   melainkan karena tidak bisa melihat bentuknya — itu measurement error
   yang mencemari data.

   Solusinya tetap terasa seperti game: kartu krem sangat terang dengan
   garis tepi stiker dan bayangan padat, bukan kotak putih formal.
   Hiasan diletakkan DI LUAR atau di tepi panggung, tidak pernah di
   belakang objek 3D.
   --------------------------------------------------------------------- */
.panggung {
  position: relative;
  background: var(--panggung);      /* polos — tanpa pola, tanpa gradasi */
  background-image: none;
  border: var(--tebal-stiker) solid var(--primer);
  border-radius: var(--radius-panggung);
  box-shadow: 0 var(--angkat) 0 var(--primer-tua);
}

/* Penanda posisi untuk viewport WebGL. Canvas dirender di belakang UI,
   elemen ini hanya memberi tahu di mana. */
.view {
  position: absolute;
  inset: 10px;
  z-index: 1;
}

.panggung-label {
  position: absolute;
  left: var(--sp-3);
  top: var(--sp-2);
  z-index: 2;
  pointer-events: none;
}

/* ---------------------------------------------------------------------
   3. Kartu opsi jawaban
   --------------------------------------------------------------------- */
.grid-opsi {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
}

/*
 * min-height WAJIB mendampingi aspect-ratio, bukan sekadar pengaman.
 * ---------------------------------------------------------------------
 * aspect-ratio baru ada di Chrome 88 / Safari 15. Di browser yang lebih
 * tua deklarasinya dibuang, dan isi kartu ini cuma <span> berposisi
 * absolut — artinya tingginya jadi NOL. Elemen .view di dalamnya ikut
 * 0×0, dan renderer melewati view berukuran nol (lihat render() di
 * renderer.js). Hasilnya: kartu pipih tanpa satu pun bentuk 3D — gejala
 * yang persis sama dengan bug ukuran canvas, lewat jalur yang berbeda.
 *
 * Di gameplay, .area-opsi sudah menimpanya dengan height:100%; yang
 * benar-benar bergantung pada aturan ini adalah grid latihan tutorial.
 */
.kartu-opsi {
  position: relative;
  display: block;
  width: 100%;
  min-height: 132px;
  aspect-ratio: 1 / 1;
  background: var(--panggung);
  border: var(--tebal-stiker) solid var(--primer);
  border-radius: var(--radius-kartu);
  box-shadow: 0 var(--angkat) 0 var(--primer-tua);
  transition: transform var(--transisi), border-color 150ms ease,
              box-shadow 150ms ease;
  touch-action: manipulation;
}

/* Terpilih: terangkat sedikit dan miring seperti stiker yang dikelupas
   (§10.6). Tanda centang ditambahkan agar warna bukan satu-satunya
   penanda (§10.8). */
.kartu-opsi[aria-pressed='true'] {
  border-color: var(--aksen);
  transform: translateY(-3px) rotate(-1deg);
  box-shadow: 0 7px 0 #C9A62E;
}

.kartu-opsi[aria-pressed='true']::after {
  content: '✓';
  position: absolute;
  right: -6px;
  top: -8px;
  /* Di atas canvas 3D (z-index 1), sama seperti .huruf-opsi — tanda
     terpilih tidak boleh bisa tertutup bentuk yang sedang digambar. */
  z-index: 2;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  background: var(--aksen);
  color: var(--tinta);
  border-radius: 50%;
  font-weight: 800;
  font-size: 15px;
  box-shadow: 0 2px 0 #C9A62E;
}

/* ---------------------------------------------------------------------
   Penanda hasil di kartu opsi — HANYA dipakai latihan tutorial.
   ---------------------------------------------------------------------
   TIDAK BOLEH dipakai di sesi Uji Diri: menandai kartu benar/salah adalah
   umpan balik performa, dan di sana siswa tidak boleh tahu apa pun sampai
   sesi berakhir (§3). tutorial.js satu-satunya yang menyetel data-hasil.

   Bentuk garis tepi ikut berbeda (padat vs titik-titik), bukan hanya
   warnanya — §10.8.
   --------------------------------------------------------------------- */
.kartu-opsi[data-hasil='benar'] {
  border-color: var(--benar);
  box-shadow: 0 var(--angkat) 0 #35A155;
}

.kartu-opsi[data-hasil='salah'] {
  border-color: var(--salah);
  box-shadow: 0 var(--angkat) 0 #C74C4C;
  animation: goyang-salah 380ms ease both;
}

/* Kartu yang SEHARUSNYA dipilih, ditunjukkan setelah siswa keliru.
   Garis titik-titik supaya jelas ini petunjuk, bukan pilihannya. */
.kartu-opsi[data-hasil='petunjuk'] {
  border-style: dashed;
  border-color: var(--benar);
}

@keyframes goyang-salah {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-7px); }
  50%      { transform: translateX(6px); }
  80%      { transform: translateX(-3px); }
}

@media (prefers-reduced-motion: reduce) {
  .kartu-opsi[data-hasil='salah'] { animation: none; }
}

.huruf-opsi {
  position: absolute;
  left: var(--sp-2);
  top: var(--sp-1);
  z-index: 2;
  font-family: var(--font-pixel);
  font-size: 14px;
  color: var(--teks-lembut);
  pointer-events: none;
}

/* ---------------------------------------------------------------------
   4. Tangga titik — progres (§10.5)
   ---------------------------------------------------------------------
   Dipakai menggantikan teks "1/20": lebih cepat dibaca sekilas dan tidak
   membebani siswa dengan hitungan sisa soal.
   --------------------------------------------------------------------- */
.tangga-titik {
  display: flex;
  gap: 4px;
  align-items: center;
  flex-wrap: wrap;
}

.titik {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--netral);
  transition: transform 200ms ease, background-color 200ms ease;
}

.titik[data-status='selesai'] { background: var(--primer); }

.titik[data-status='kini'] {
  background: var(--aksen);
  transform: scale(1.6);
  box-shadow: 0 0 0 2px rgba(255, 216, 77, 0.40);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--aksen) 40%, transparent);
}

/* ---------------------------------------------------------------------
   5. Pil (timer, lencana)
   --------------------------------------------------------------------- */
.pil {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 6px 14px;
  min-height: 32px;
  border-radius: var(--radius-pil);
  background: var(--panggung);
  border: 2px solid var(--primer);
  font-family: var(--font-pixel);
  font-size: 14px;
  color: var(--teks);
}

/* Waktu menipis. Warna saja tidak cukup (§10.8) — ikon jam ikut berubah
   dan ada teks untuk pembaca layar. */
.pil-timer[data-sisa='menipis'] {
  border-color: var(--salah);
  color: var(--tinta);
  background: #FFE0DC;
  background: color-mix(in srgb, var(--salah) 22%, var(--panggung));
  animation: denyut 1s ease-in-out infinite;
}

@keyframes denyut {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.05); }
}

/* ---------------------------------------------------------------------
   6. Kartu umum
   --------------------------------------------------------------------- */
.kartu {
  background: var(--panggung);
  border: var(--tebal-stiker) solid var(--primer);
  border-radius: var(--radius-kartu);
  box-shadow: 0 var(--angkat) 0 var(--primer-tua);
  padding: var(--sp-4);
}

.kartu-lembut {
  background: var(--cad-panggung-primer88);
  background: color-mix(in srgb, var(--panggung) 88%, var(--primer));
  border: 2px dashed var(--primer);
  border-radius: var(--radius-kartu);
  padding: var(--sp-3) var(--sp-4);
  box-shadow: none;
}

/* ---------------------------------------------------------------------
   7. Isian formulir
   --------------------------------------------------------------------- */
.bidang { display: block; margin-bottom: var(--sp-4); }

.bidang > .label { display: block; margin-bottom: 6px; }

.isian {
  display: block;
  width: 100%;
  min-height: var(--sentuh);
  padding: 10px 14px;
  background: #fff;
  color: var(--teks);
  /* --primer-tua, bukan --primer: batas bidang formulir termasuk komponen
     non-teks dan wajib ≥3:1 (WCAG 1.4.11). --primer di atas putih hanya
     mencapai 2,60:1 — bidangnya terlihat mengambang tanpa tepi yang jelas
     bagi pengguna dengan penglihatan rendah. */
  border: 2px solid var(--primer-tua);
  border-radius: var(--radius-kecil);
  font-size: 16px;   /* ≥16px mencegah iOS memperbesar layar saat difokus */
}

.isian::placeholder { color: var(--teks-lembut); opacity: 1; }

/* Di tema Manis, --salah dan --primer-tua sama-sama kemerahan sehingga
   perubahan warna saja nyaris tak terlihat. Tepinya dipertebal agar
   bidang bermasalah menonjol secara BENTUK, bukan hanya warna — dan
   pesan galat tetap membawa ikon ⚠ serta teks (§10.8). */
.isian[aria-invalid='true'] {
  border-color: var(--salah);
  border-width: 3px;
  background: #FFF4F4;
  background: color-mix(in srgb, var(--salah) 8%, #fff);
}

.pesan-galat {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
  font-size: var(--f-label);
  font-weight: 700;
  color: var(--tinta);
}

.pesan-galat::before { content: '⚠'; }   /* ikon, bukan hanya warna */

/* Kotak centang berukuran nyaman disentuh. */
.centang {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  min-height: var(--sentuh);
  cursor: pointer;
}

.centang input {
  width: 26px;
  height: 26px;
  accent-color: var(--primer);
  flex: 0 0 auto;
  margin-top: 2px;
}

/* ---------------------------------------------------------------------
   8. Modal
   --------------------------------------------------------------------- */
.tirai {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  padding: var(--sp-4);
  background: rgba(58, 32, 48, 0.55);
  background: color-mix(in srgb, var(--tinta) 55%, transparent);
  animation: pudar-masuk 180ms ease both;
}

.modal {
  width: min(420px, 100%);
  background: var(--panggung);
  border: var(--tebal-stiker) solid var(--primer);
  border-radius: var(--radius-panggung);
  box-shadow: 0 6px 0 var(--primer-tua);
  padding: var(--sp-5);
  animation: muncul 220ms cubic-bezier(.34, 1.32, .64, 1) both;
}

@keyframes pudar-masuk { from { opacity: 0; } to { opacity: 1; } }
@keyframes muncul {
  from { opacity: 0; transform: translateY(14px) scale(.96); }
  to   { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------------------
   9. Toast
   --------------------------------------------------------------------- */
.toast-wadah {
  position: fixed;
  left: 50%;
  bottom: calc(var(--sp-5) + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  width: min(420px, calc(100% - 32px));
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 12px 16px;
  background: var(--panggung);
  color: var(--teks);
  border: 2px solid var(--primer);
  border-radius: var(--radius-kecil);
  box-shadow: 0 3px 0 var(--primer-tua);
  font-size: var(--f-body);
  animation: muncul 220ms cubic-bezier(.34, 1.32, .64, 1) both;
}

.toast[data-jenis='galat'] { border-color: var(--salah); box-shadow: 0 3px 0 #C74C4C; }
.toast[data-jenis='sukses'] { border-color: var(--benar); box-shadow: 0 3px 0 #35A155; }

/* ---------------------------------------------------------------------
   10. Hiasan & maskot
   ---------------------------------------------------------------------
   Diletakkan di luar panggung (§10.3) dan tidak pernah menghalangi
   sentuhan.
   --------------------------------------------------------------------- */
.stiker {
  position: absolute;
  pointer-events: none;
  user-select: none;
  z-index: 2;
}

.stiker-melayang { animation: melayang 3.4s ease-in-out infinite; }

@keyframes melayang {
  0%, 100% { transform: translateY(0) rotate(-3deg); }
  50%      { transform: translateY(-7px) rotate(3deg); }
}

.maskot { width: 92px; image-rendering: auto; }
.maskot-kecil { width: 60px; }

/* Lencana status terkunci — memakai ikon, bukan hanya warna. */
.gembok {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: var(--radius-pil);
  background: #E7E1E7;
  background: color-mix(in srgb, var(--netral) 45%, var(--panggung));
  color: var(--tinta);
  font-size: var(--f-label);
  font-weight: 700;
}

.gembok::before { content: '🔒'; }
