/* ==========================================================================
   ANIMASI KONEKSI SISTEM — overlay di atas foto RTP
   ==========================================================================
   Foto tetap satu berkas statis. Seluruh animasi berada di .fx-layer yang
   transparan di atasnya, jadi berkas fotonya tidak pernah diubah.

   Peran warna dipatuhi ketat:
     EMAS   = mesin / antarmuka RTP
     BIRU   = data yang bergerak, koneksi, sinkronisasi
     PUTIH  = kilatan scanner
     HIJAU  = khusus sukses

   Koordinat memakai persen terhadap kotak foto, bukan piksel tetap, supaya
   posisinya tetap benar saat foto mengecil atau membesar.
   ========================================================================== */

:root {
  --fx-blue: #168bff;
  --fx-blue-light: #eaf7ff;
  --fx-blue-glow: rgba(var(--hud-blue-rgb), .30);
  --fx-gold: rgba(var(--hud-gold-rgb), .75);
  --fx-green: #39e58c;
  --fx-green-glow: rgba(57, 229, 140, .22);

  /* Titik-titik penting pada foto. Diubah di sini kalau fotonya diganti.
     Diukur langsung dari piksel foto MNJ yang sekarang: cincin RTP terbaca
     membentang 36%-59% menurun pada kolom tengah, jadi pusatnya 47,5% dan
     garis tengahnya sekitar 23% tinggi gambar. */
  --fx-user-x: 17%;
  --fx-system-x: 53%;
  --fx-core-y: 47.5%;
  --fx-beam-width: 30%;
}

/* Peredup tipis. Fotonya sendiri sudah sangat ramai oleh cincin emas dan
   cahaya biru; tanpa ini garis energi dan cincin animasi tenggelam dan tidak
   terbaca. Hanya aktif selama proses, dan menghilang lagi setelah terhubung
   supaya fotonya kembali utuh. */
.fx-layer::before {
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 52%, rgba(2, 6, 14, .30) 0%, rgba(2, 6, 14, .62) 70%);
  content: "";
  opacity: 0;
  transition: opacity 320ms ease;
}

.is-connecting .fx-layer::before,
.is-syncing .fx-layer::before,
.is-verifying .fx-layer::before { opacity: 1; }

/* Lapisan animasi menempati kotak yang sama persis dengan fotonya. Foto MNJ
   berbanding 1:1 dan wadahnya juga 1:1, jadi inset 0 sudah pas. */
.fx-layer {
  position: absolute;
  z-index: 3;
  inset: 0;
  pointer-events: none;
}

/* ==========================================================================
   GARIS ENERGI
   ========================================================================== */

.energy-line {
  position: absolute;
  top: var(--fx-core-y);
  width: var(--fx-beam-width);
  height: 4px;
  border-radius: 2px;
  opacity: 0;
  transform: scaleX(0);
  transform-origin: left center;
  background: linear-gradient(90deg, transparent, var(--fx-blue), #fff, var(--fx-blue), transparent);
  filter: drop-shadow(0 0 7px rgba(var(--hud-blue-rgb), .85));
}

.energy-user { left: var(--fx-user-x); }
.energy-system { left: var(--fx-system-x); }

/* Titik energi di ujung garis. Satu per garis, bukan particle engine. */
.energy-head {
  position: absolute;
  top: 50%;
  left: 0;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  opacity: 0;
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 0 8px var(--fx-blue));
  background: radial-gradient(circle, #fff 0%, var(--fx-blue-light) 35%, var(--fx-blue) 60%, transparent 72%);
}

.is-connecting .energy-user { animation: energyTravel .7s ease-out forwards; }

/* -- kepala energi lewat TIGA KALI ---------------------------------------
   Satu lintasan tunggal terbaca seperti kedipan: titiknya muncul, lewat,
   hilang, dan mata belum sempat menyimpulkan apa pun. Tiga lintasan
   berturut-turut terbaca sebagai ALIRAN - ada yang benar-benar dikirim
   melalui jalur itu, berulang, seperti paket data menyusul satu sama lain.

   Yang diulang hanya KEPALANYA. Garisnya sendiri tetap sekali: garis itu
   jalurnya, dan jalur yang digambar ulang tiga kali justru terlihat seperti
   sambungan yang putus-nyambung.

   Animasinya sengaja ditulis identik pada dua selektor fase. Selama nama
   dan parameternya tidak berubah, peramban meneruskan animasi yang sedang
   berjalan alih-alih memulainya dari nol - jadi hitungan tiganya tidak
   ter-reset saat tombol berpindah dari MENGHUBUNGKAN ke SINKRONISASI. */
.is-connecting .energy-user .energy-head,
.is-syncing .energy-user .energy-head { animation: energyHeadTravel .52s ease-out 3 forwards; }

/* Garis pertama tetap menyala selama fase berikutnya supaya jalurnya
   terbaca sebagai sambungan yang sudah terbentuk, bukan berkedip. */
.is-syncing .energy-user,
.is-verifying .energy-user,
.is-connected .energy-user { opacity: 1; transform: scaleX(1); }

.is-verifying .energy-system { animation: energyTravel .7s ease-out forwards; }
.is-verifying .energy-system .energy-head,
.is-connected .energy-system .energy-head { animation: energyHeadTravel .52s ease-out 3 forwards; }
.is-connected .energy-system { opacity: 1; transform: scaleX(1); }

@keyframes energyTravel {
  from { opacity: 0; transform: scaleX(0); }
  20% { opacity: 1; }
  to { opacity: 1; transform: scaleX(1); }
}

@keyframes energyHeadTravel {
  from { opacity: 0; transform: translate(-50%, -50%); }
  15% { opacity: 1; }
  85% { opacity: 1; }
  to { opacity: 0; transform: translate(calc(-50% + 100cqw), -50%); }
}

/* Lebar garis dipakai sebagai satuan gerak kepala energi. */
.energy-line { container-type: size; }

/* ==========================================================================
   INTI RTP
   ========================================================================== */

.rtp-core-fx {
  position: absolute;
  top: var(--fx-core-y);
  left: 50%;
  /* Disamakan dengan garis tengah cincin pada fotonya, bukan angka kira-kira. */
  width: 24%;
  aspect-ratio: 1;
  opacity: 0;
  transform: translate(-50%, -50%);
  transition: opacity var(--hud-hover, 300ms) ease;
}

.is-connecting .rtp-core-fx,
.is-syncing .rtp-core-fx,
.is-verifying .rtp-core-fx,
.is-connected .rtp-core-fx { opacity: 1; }

/* Cincin dibiarkan transparan supaya fotonya tetap terlihat. */
.ring {
  position: absolute;
  inset: 0;
  border: 3px solid var(--fx-gold);
  border-radius: 50%;
  filter: drop-shadow(0 0 6px rgba(var(--hud-gold-rgb), .55));
}

.ring-2 {
  inset: 13%;
  border-color: var(--fx-blue-light);
  border-style: dashed;
  filter: drop-shadow(0 0 7px var(--fx-blue));
}

.is-connecting .ring-1,
.is-syncing .ring-1,
.is-verifying .ring-1 { animation: coreRotate 1.6s linear infinite; }

.is-connecting .ring-2,
.is-syncing .ring-2,
.is-verifying .ring-2 { animation: coreRotateReverse 1.2s linear infinite; }

@keyframes coreRotate { to { transform: rotate(360deg); } }
@keyframes coreRotateReverse { to { transform: rotate(-360deg); } }

/* ==========================================================================
   SCANNER
   ==========================================================================
   Indikator tak tentu. Backend tidak memberi angka kemajuan, jadi tidak ada
   bilangan persen yang ditampilkan - itu akan jadi kemajuan palsu.
   ========================================================================== */

.scanner {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: 50%;
  opacity: 0;
}

.scanner::before {
  position: absolute;
  top: 0;
  left: -60%;
  width: 60%;
  height: 100%;
  background: linear-gradient(90deg, transparent, var(--fx-blue), #fff, var(--fx-blue), transparent);
  content: "";
  opacity: .85;
}

.is-syncing .scanner,
.is-verifying .scanner { opacity: 1; }
.is-syncing .scanner::before,
.is-verifying .scanner::before { animation: scannerSweep 1.15s linear infinite; }

@keyframes scannerSweep {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(280%, 0, 0); }
}

/* ==========================================================================
   PARTIKEL
   ==========================================================================
   8 di desktop, 3 di layar sempit. Dekoratif saja dan berhenti begitu
   koneksi selesai.
   ========================================================================== */

.fx-particles { position: absolute; inset: 0; }

.fx-particles i {
  position: absolute;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--fx-blue-light);
  box-shadow: 0 0 6px var(--fx-blue);
  opacity: 0;
}

.fx-particles i:nth-child(1) { top: 42%; left: 32%; }
.fx-particles i:nth-child(2) { top: 66%; left: 38%; }
.fx-particles i:nth-child(3) { top: 50%; left: 45%; }
.fx-particles i:nth-child(4) { top: 38%; left: 58%; }
.fx-particles i:nth-child(5) { top: 70%; left: 62%; }
.fx-particles i:nth-child(6) { top: 54%; left: 70%; }
.fx-particles i:nth-child(7) { top: 46%; left: 26%; }
.fx-particles i:nth-child(8) { top: 60%; left: 76%; }

.is-syncing .fx-particles i,
.is-verifying .fx-particles i { animation: statusPulse 1.8s ease-in-out infinite; }
.is-syncing .fx-particles i:nth-child(even) { animation-delay: -.9s; }

@keyframes statusPulse {
  0%, 100% { opacity: 0; transform: translate3d(0, 0, 0) scale(.6); }
  50% { opacity: .9; transform: translate3d(0, -8px, 0) scale(1); }
}

/* ==========================================================================
   STATUS TERHUBUNG DI ATAS FOTO
   ========================================================================== */

.connected-status {
  position: absolute;
  bottom: 7%;
  left: 50%;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 9px 16px;
  border: 1px solid var(--fx-green);
  background: rgba(5, 15, 12, .88);
  box-shadow: 0 0 18px var(--fx-green-glow);
  color: #fff;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .07em;
  white-space: nowrap;
  opacity: 0;
  transform: translateX(-50%) scale(.9);
}

.connected-status .check {
  display: grid;
  width: 20px;
  height: 20px;
  place-items: center;
  border: 1px solid var(--fx-green);
  border-radius: 50%;
  color: var(--fx-green);
  transform: scale(.7);
}

.is-connected .connected-status { animation: connectedIn .5s ease forwards; }
.is-connected .connected-status .check { animation: checkPop .45s var(--hud-ease, ease) .12s forwards; }

@keyframes connectedIn {
  to { opacity: 1; transform: translateX(-50%) scale(1); }
}

@keyframes checkPop {
  60% { transform: scale(1.12); }
  to { transform: scale(1); }
}

/* Sapuan hijau satu kali di tepi panel. Tidak diulang. */
.is-connected .fx-layer::after {
  position: absolute;
  inset: 0;
  border: 1.5px solid var(--fx-green);
  content: "";
  opacity: 0;
  animation: successSweep .6s ease forwards;
}

@keyframes successSweep {
  0% { opacity: 0; clip-path: inset(0 100% 0 0); }
  45% { opacity: .9; }
  100% { opacity: 0; clip-path: inset(0 0 0 0); }
}

/* ==========================================================================
   GAGAL
   ========================================================================== */

.ai-visual.is-error { border-color: rgba(255, 107, 107, .55); }

.is-error .connected-status {
  border-color: rgba(255, 107, 107, .75);
  box-shadow: none;
  opacity: 1;
  transform: translateX(-50%) scale(1);
}

.is-error .connected-status .check { border-color: rgba(255, 107, 107, .75); color: #ff6b6b; transform: scale(1); }

/* Ikon centang diganti tanda seru saat gagal. Teks lencananya sendiri diatur
   JavaScript, bukan lewat content CSS, supaya isinya ikut terbaca alat bantu
   dan tidak ada teks tersembunyi yang menyesatkan. */
.is-error .connected-status .check svg { display: none; }
.is-error .connected-status .check::before { content: "!"; font-size: 13px; font-weight: 900; }

/* ==========================================================================
   TEKS STATUS
   ========================================================================== */

.connection-status-text {
  position: absolute;
  z-index: 4;
  right: 0;
  bottom: 10px;
  left: 0;
  margin: 0;
  color: var(--hud-blue-bright, var(--hud-blue-bright));
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  text-align: center;
  text-transform: uppercase;
}

/* Saat terhubung, lencana di atas foto sudah menyatakan hal yang sama.
   Teksnya disembunyikan secara visual saja - tetap ada di DOM supaya pembaca
   layar tetap mengumumkannya lewat aria-live. */
.ai-visual.is-connected .connection-status-text { opacity: 0; }
.ai-visual.is-error .connection-status-text { color: #ff6b6b; }

/* ==========================================================================
   MODE RINGAN DI LAYAR SEMPIT
   ==========================================================================
   Satu cincin, satu scanner, tanpa partikel - sesuai batasan perangkat
   kelas menengah.
   ========================================================================== */

@media (max-width: 767px) {
  .ring-2 { display: none; }
  .fx-particles i:nth-child(n + 4) { display: none; }
  .energy-line { height: 2px; }
  .connected-status { bottom: 5%; padding: 7px 12px; font-size: 10px; }
  .fx-particles i { box-shadow: none; }
}

/* ==========================================================================
   HORMATI PREFERENSI GERAK MINIM
   ==========================================================================
   Teks status, centang sukses, dan pergantian warna tetap ada; yang dimatikan
   hanya gerakannya.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .energy-line,
  .energy-head,
  .ring,
  .scanner::before,
  .fx-particles i,
  .connected-status,
  .connected-status .check,
  .is-connected .fx-layer::after { animation: none !important; }

  .fx-particles { display: none; }
  .is-connecting .energy-user,
  .is-syncing .energy-user,
  .is-verifying .energy-user,
  .is-connected .energy-user,
  .is-verifying .energy-system,
  .is-connected .energy-system { opacity: 1; transform: scaleX(1); }
  .is-connected .connected-status { opacity: 1; transform: translateX(-50%) scale(1); }
  .is-connected .connected-status .check { transform: scale(1); }
}

/* Panel di luar layar: animasi dihentikan, bukan dibiarkan jalan terus. */
.ai-visual.is-offscreen .fx-layer *,
.ai-visual.is-offscreen .fx-layer *::before,
.ai-visual.is-offscreen .fx-layer *::after { animation-play-state: paused !important; }

/* ==========================================================================
   NODE MENGORBIT — DUA SISTEM YANG SALING MENCARI
   ==========================================================================
   Satu titik terang mengelilingi cincin luar, satu lagi mengelilingi cincin
   dalam ke arah berlawanan. Arah yang berlawanan itu yang penting: dua titik
   searah terbaca sebagai hiasan berputar, sementara yang berpapasan terbaca
   sebagai dua pihak yang sedang saling menghubungi.

   transform-origin ditaruh di PUSAT cincin, bukan di titik itu sendiri - jadi
   titiknya mengitari lingkaran, bukan berputar di tempat. Angkanya = jari-jari
   cincin diukur dari sudut kiri atas kotak titik.

   Dipakai properti `rotate`, bukan `transform`: .ring sudah memakai transform
   untuk animasi coreRotate saat menghubungkan, dan dua animasi tidak bisa
   sama-sama menulis properti yang sama.
   ========================================================================== */

/* Titik orbit digambar sebagai LAPISAN SEUKURAN CINCIN yang diputar pada
   pusatnya sendiri, bukan sebagai titik kecil dengan transform-origin sejauh
   jari-jari.

   Cara lama menuntut angka piksel tetap (4.5px 59.5px) yang hanya benar selama
   cincinnya berukuran 110px. Begitu ukurannya berubah - layar lain, breakpoint
   lain - titiknya melenceng keluar dari garis. Dengan lapisan penuh, pusat
   putarnya selalu pusat cincin berapa pun ukurannya, dan tidak ada satu pun
   angka yang perlu disetel ulang. */
.ring-1::after,
.ring-2::after,
.ring-3::after {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  content: "";
}

.ring-1::after {
  background: radial-gradient(circle 7px at 50% 0, #ffffff 0 20%, rgb(var(--hud-tepi-rgb)) 40%, rgba(var(--hud-tepi-rgb), 0) 72%);
  filter: drop-shadow(0 0 7px rgba(var(--hud-tepi-rgb), .9));
  animation: orbit-node 5.2s linear infinite;
}

/* Berlawanan arah dengan cincin luar. Dua titik searah terbaca sebagai hiasan
   berputar; yang berpapasan terbaca sebagai dua pihak yang saling memanggil. */
.ring-2::after {
  background: radial-gradient(circle 6px at 50% 0, #ffffff 0 20%, rgb(var(--hud-tepi-rgb)) 40%, rgba(var(--hud-tepi-rgb), 0) 72%);
  filter: drop-shadow(0 0 6px rgba(var(--hud-tepi-rgb), .75));
  opacity: .8;
  animation: orbit-node 3.4s linear infinite reverse;
}

/* Cincin terluar: orbitnya magenta dan paling lambat. Yang paling lebar
   berputar paling pelan - itu yang membuat ketiganya terbaca sebagai satu
   sistem berlapis, bukan tiga animasi yang kebetulan bertumpuk. */
.ring-3 {
  inset: -17%;
  border-width: 4px;
  /* .42 -> .9. Alfa serendah itu membuat magentanya melebur ke foto ungu di
     belakangnya; yang terlihat cuma bayangannya, bukan garisnya. */
  border-color: rgba(var(--hud-sorot-rgb), .9);
  filter:
    drop-shadow(0 0 10px rgba(var(--hud-sorot-rgb), .85))
    drop-shadow(0 0 26px rgba(var(--hud-sorot-rgb), .45));
}

.ring-3::after {
  /* 6px -> 11px, dan intinya dibuat putih. Bola berwarna penuh di atas garis
     yang kini juga terang jadi sulit dibedakan dari garisnya sendiri; inti
     putih yang meluruh ke magenta membuat bolanya terbaca sebagai benda
     terpisah yang sedang berjalan di atas garis itu. */
  background: radial-gradient(
    circle 11px at 50% 0,
    #ffffff 0 22%,
    rgb(var(--hud-sorot-rgb)) 38%,
    rgba(var(--hud-sorot-rgb), 0) 72%
  );
  filter:
    drop-shadow(0 0 12px rgba(var(--hud-sorot-rgb), 1))
    drop-shadow(0 0 30px rgba(var(--hud-sorot-rgb), .6));
  animation: orbit-node 7.8s linear infinite;
}

@keyframes orbit-node {
  from { rotate: 0deg; }
  to { rotate: 360deg; }
}

@media (prefers-reduced-motion: reduce) {
  .ring-1::after,
  .ring-2::after,
  .ring-3::after { animation: none; }
}

/* --------------------------------------------------------------------------
   SE8: cincin lime, lebih tebal, berpendar.
   Cincin luar tadinya memakai --fx-gold yang di tema ini berarti ungu - warna
   yang sama dengan foto di belakangnya, sehingga tepinya melebur dan setiap
   ketidakcocokan posisi foto langsung terlihat. Lime memberi batas yang tegas,
   dan pendarnya menutup selisih beberapa piksel itu.
   -------------------------------------------------------------------------- */

.ring-1 {
  border-width: 4.5px;
  border-color: rgb(var(--hud-tepi-rgb));
  filter:
    drop-shadow(0 0 9px rgba(var(--hud-tepi-rgb), .95))
    drop-shadow(0 0 22px rgba(var(--hud-tepi-rgb), .5));
}

.ring-3 {
  border-width: 4.5px;
  border-color: rgb(var(--hud-sorot-rgb));
}

.ring-2 {
  border-width: 3px;
  border-color: rgba(var(--hud-tepi-rgb), .85);
  filter: drop-shadow(0 0 8px rgba(var(--hud-tepi-rgb), .7));
}

/* --------------------------------------------------------------------------
   MNJ: tepi orb dicampur biru elektrik, bukan emas semua.
   --hud-tepi-rgb bawaan MNJ kebetulan senada dengan --hud-gold-rgb (keduanya
   emas), jadi cincin dan jalur di jalur-3d ikut terbaca emas polos. Ditimpa
   ke --hud-cyan-rgb (#28d7ff) - biru yang SAMA dipakai garis sirkuit header
   (.circuit__trace) dan sebagian besar border di seluruh halaman MNJ, bukan
   --hud-blue-rgb yang sedikit lebih gelap. Dibatasi ke dalam .ai-visual saja
   supaya tombol dan elemen lain yang juga memakai --hud-tepi-rgb tidak ikut
   berubah. Inti dan alas orb tetap emas (--hud-gold-rgb tidak disentuh) -
   hasilnya emas di tengah, biru di tepi/cincin/jalur.
   -------------------------------------------------------------------------- */
[data-theme="navy_gold"] .ai-visual {
  --hud-tepi-rgb: var(--hud-cyan-rgb);
}

/* ==========================================================================
   JALUR SISTEM — VISUAL HERO DIGAMBAR KODE (SEMUA WLB)
   ==========================================================================
   Awalnya dibuat khusus tema ungu-lime (SE8), lalu diperluas ke ketiga WLB -
   MNJ dan SLG tidak lagi memakai foto hero, gayanya sama, warnanya ikut
   --hud-tepi-rgb/--hud-sorot-rgb masing-masing tema. Alasannya bukan selera:

   Selama visualnya berupa foto, inti RTP digambar di dalam foto sementara
   cincin digambar CSS, lalu keduanya dicocokkan dengan menebak - itulah asal
   semua penyetelan --fx-foto-geser-y yang berulang. Di sini inti, cincin, dan
   jalur memakai satu sistem koordinat yang sama (viewBox 400x400, pusat di
   200,200), jadi keduanya sepusat secara konstruksi dan tidak ada yang perlu
   disetel lagi.

   Sampingannya: berkasnya 0 KB, tajam di resolusi berapa pun, dan warnanya
   ikut variabel tema - WLB baru cukup mengganti beberapa baris warna.

   PAKET DATA memakai stroke-dashoffset pada SALINAN jalur yang sama, bukan
   offset-path. Satu goresan pendek (dasharray 16 600) yang digeser terus akan
   mengikuti lekuk jalurnya dengan presisi sempurna tanpa perlu satu koordinat
   tambahan pun, dan tetap benar kalau jalurnya nanti diubah bentuknya.
   ========================================================================== */

/* ---- panggung 3D ----
   perspective menentukan seberapa kuat kedalamannya terasa. 1100px cukup jauh
   untuk terbaca sebagai ruang, tapi tidak sampai membuat lapisan tepi melar
   seperti lensa lebar.

   Seluruh tumpukan dimiringkan sedikit lalu berayun pelan. Kemiringan saja
   tidak cukup: tanpa gerak, mata tetap membacanya sebagai gambar datar yang
   kebetulan miring. Justru pergeseran BERBEDA antar lapisan saat berayun -
   parallaks - itulah yang menyampaikan kedalaman. */
.jalur-3d {
  position: absolute;
  z-index: 1;
  inset: 0;
  display: none;
  perspective: 1100px;
  perspective-origin: 50% 50%;
}

.jalur-3d { display: block; }
.ai-visual-media { visibility: hidden; }

.jalur-lapis {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
}


/* Lapisan belakang sedikit lebih redup dan kabur - dua isyarat kedalaman yang
   dipakai mata bahkan sebelum parallaks terbaca. */
.jalur-l1 { opacity: .78; filter: blur(.7px); }
.jalur-l2 { opacity: .94; }

/* Kemiringan 3D dicabut - hasilnya dinilai jelek dan versi datarnya lebih
   baik. Lapisannya tetap dipertahankan: pemisahannya masih berguna untuk
   memberi kedalaman lewat kepekatan dan kabur, tanpa memiringkan apa pun. */
.jalur-3d {
  perspective: none;
  transform-style: flat;
}

/* ---- lingkar latar ---- */

.jalur-latar circle {
  fill: none;
  stroke: rgba(var(--hud-gold-rgb), .2);
  stroke-width: 1;
}

/* ---- jalur dasar ---- */

.jalur-utama path {
  fill: none;
  stroke: rgba(var(--hud-gold-rgb), .5);
  stroke-width: 2;
  /* Ujung dan sambungan dibuat siku, bukan bulat. Pada jalur bersudut, ujung
     bulat membulatkan tiap belokan dan lekuk 45 derajatnya jadi tumpul -
     justru bentuk itu yang ingin ditiru dari sirkuit di header. */
  stroke-linecap: butt;
  stroke-linejoin: miter;
}

/* ---- paket data ---- */

.jalur-paket use {
  fill: none;
  stroke: rgb(var(--hud-tepi-rgb));
  stroke-width: 3.2;
  stroke-linecap: round;
  /* Goresan 16 dengan celah 600: hanya satu paket terlihat per jalur pada satu
     waktu, apa pun panjang jalurnya. */
  stroke-dasharray: 16 600;
  filter: drop-shadow(0 0 5px rgba(var(--hud-tepi-rgb), .9));
  opacity: 0;
}

/* Tiga jalur kiri berangkat lebih dulu, tiga jalur kanan menyusul - jeda itu
   yang membuatnya terbaca sebagai satu paket menyeberangi inti, bukan enam
   paket yang kebetulan bergerak bersamaan. */
.jalur-paket use:nth-child(1) { animation: paket-jalan 2.6s linear infinite; }
.jalur-paket use:nth-child(2) { animation: paket-jalan 2.2s linear .3s infinite; }
.jalur-paket use:nth-child(3) { animation: paket-jalan 2.9s linear .15s infinite; }
.jalur-paket use:nth-child(4) { animation: paket-jalan 2.6s linear .9s infinite; }
.jalur-paket use:nth-child(5) { animation: paket-jalan 2.2s linear 1.1s infinite; }
.jalur-paket use:nth-child(6) { animation: paket-jalan 2.9s linear .95s infinite; }

@keyframes paket-jalan {
  0% { stroke-dashoffset: 616; opacity: 0; }
  8% { opacity: 1; }
  92% { opacity: 1; }
  100% { stroke-dashoffset: 0; opacity: 0; }
}

/* ---- simpul ---- */

.jalur-simpul circle {
  fill: rgb(var(--hud-tepi-rgb));
  filter: drop-shadow(0 0 6px rgba(var(--hud-tepi-rgb), .85));
  animation: simpul-denyut 2.4s ease-in-out infinite;
}

.jalur-simpul circle:nth-child(2),
.jalur-simpul circle:nth-child(5) {
  fill: rgb(var(--hud-sorot-rgb));
  filter: drop-shadow(0 0 8px rgba(var(--hud-sorot-rgb), .9));
}

.jalur-simpul circle:nth-child(3) { animation-delay: .4s; }
.jalur-simpul circle:nth-child(4) { animation-delay: .8s; }
.jalur-simpul circle:nth-child(5) { animation-delay: 1.2s; }
.jalur-simpul circle:nth-child(6) { animation-delay: 1.6s; }

@keyframes simpul-denyut {
  0%, 100% { opacity: .55; }
  50% { opacity: 1; }
}

/* ---- ikon user (kiri) dan sistem (kanan) ---- */

.ikon-alas {
  fill: rgba(10, 5, 22, .85);
  stroke: rgba(var(--hud-tepi-rgb), .5);
  stroke-width: 1.5;
}

.ikon-sistem .ikon-alas { stroke: rgba(var(--hud-sorot-rgb), .55); }

.ikon-garis {
  fill: none;
  stroke: rgb(var(--hud-tepi-rgb));
  stroke-width: 2.4;
  stroke-linecap: round;
}

.ikon-sistem .ikon-garis { stroke: rgb(var(--hud-sorot-rgb)); }

.ikon-titik { fill: rgb(var(--hud-sorot-rgb)); }

/* Ikon SELALU penuh. Versi sebelumnya menurunkan opacity ke .68 untuk memberi
   kesan berdenyut - tapi ikon adalah dua ujung yang paling perlu terbaca, dan
   meredupkannya berarti membuat hal terpenting jadi paling samar separuh waktu.

   Denyutnya dipindah ke PENDAR: terang-redupnya cahaya di sekitar ikon, bukan
   kepekatan ikonnya sendiri. */
.ikon-user,
.ikon-sistem { opacity: 1; }

.ikon-user { animation: ikon-pendar 2.6s ease-in-out infinite; }
.ikon-sistem { animation: ikon-pendar 2.6s ease-in-out 1.3s infinite; }

@keyframes ikon-pendar {
  0%, 100% { filter: drop-shadow(0 0 3px rgba(var(--hud-tepi-rgb), .35)); }
  50% { filter: drop-shadow(0 0 10px rgba(var(--hud-tepi-rgb), .8)); }
}

/* ---- teks RTP di inti, dan ceklis saat terhubung ---- */

.inti-teks {
  fill: rgb(var(--hud-tepi-rgb));
  font-family: inherit;
  font-size: 30px;
  font-weight: 900;
  letter-spacing: 2px;
  text-anchor: middle;
  dominant-baseline: central;
  filter: drop-shadow(0 0 8px rgba(var(--hud-tepi-rgb), .7));
}

.inti-ceklis {
  fill: none;
  stroke: #2ee86a;
  stroke-width: 6;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* Disembunyikan lewat dasharray, bukan display: none. Dengan begini ia bisa
     TERGAMBAR dari pangkal ke ujung saat muncul - centang yang tiba-tiba ada
     terasa seperti gambar diganti, centang yang digoreskan terasa seperti
     sesuatu baru saja selesai diperiksa. */
  stroke-dasharray: 54;
  stroke-dashoffset: 54;
  opacity: 0;
  filter: drop-shadow(0 0 10px rgba(46, 232, 106, .85));
}

.ai-visual.is-connected .inti-teks {
  opacity: 0;
  transition: opacity .25s ease;
}

.ai-visual.is-connected .inti-ceklis {
  opacity: 1;
  stroke-dashoffset: 0;
  transition: stroke-dashoffset .45s ease-out .2s, opacity .2s ease .2s;
}

/* Saat terhubung, inti berubah hijau dan jalur ikut tenang. */
.ai-visual.is-connected .inti-tepi {
  stroke: rgba(46, 232, 106, .8);
}

.ai-visual.is-connected .jalur-utama path {
  stroke: rgba(46, 232, 106, .6);
  transition: stroke .4s ease;
}

.ai-visual.is-connected .jalur-paket use {
  animation: none;
  opacity: 0;
}

/* ---- bingkai kotak dimatikan: bentuknya bulat, bingkainya harus ikut ---- */

.ai-visual {
  border: 0;
  background: none;
  box-shadow: none;
}

.ai-visual::before,
.ai-visual::after,
.visual-grid {
  display: none;
}

/* ==========================================================================
   TAHAP: tiap keadaan punya tanda visualnya sendiri, bukan sekadar lebih cepat
   ========================================================================== */

/* Diam: jalur redup, paket berjalan pelan - sistemnya hidup tapi santai. */
.ai-visual.is-idle .jalur-paket use {
  animation-duration: 4.4s;
  opacity: .5;
}

/* Menghubungkan: jalur menyala, paket deras. */
.ai-visual.is-connecting .jalur-utama path,
.ai-visual.is-syncing .jalur-utama path {
  stroke: rgba(var(--hud-tepi-rgb), .75);
  transition: stroke .4s ease;
}

.ai-visual.is-syncing .jalur-paket use {
  animation-duration: 1.1s;
  stroke-width: 4;
}

/* Verifikasi: semua jalur menyala penuh sekaligus lalu tenang - berhenti
   serentak jauh lebih terbaca sebagai "selesai" daripada centang. */
.ai-visual.is-verifying .jalur-utama path {
  stroke: rgb(var(--hud-tepi-rgb));
  /* Pendar diturunkan 7px -> 4px. Enam jalur bertemu di satu titik, dan
     pendarnya menumpuk di sana - pada 7px tumpukannya cukup pekat untuk
     memutihkan bagian tengah. */
  filter: drop-shadow(0 0 4px rgba(var(--hud-tepi-rgb), .6));
}

.ai-visual.is-verifying .jalur-paket use {
  animation: none;
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .jalur-paket use { animation: none; opacity: .85; stroke-dashoffset: 300; }
  .jalur-simpul circle { animation: none; opacity: .9; }
}

/* ---- alas, gerigi, dan inti statis ---- */

.alas-tengah { stop-color: rgba(var(--hud-gold-rgb), .22); }
.alas-tepi   { stop-color: rgba(var(--hud-gold-rgb), .1); }
.alas-luar   { stop-color: rgba(8, 4, 18, .92); }

.inti-terang { stop-color: rgba(var(--hud-gold-rgb), .5); }
.inti-gelap  { stop-color: rgba(10, 5, 22, .96); }

/* Piringan terluar diberi tepi tipis yang timbul.
   ==============================================
   Kesan timbul dibuat dari DUA bayangan berlawanan arah pada satu goresan,
   meniru cara benda nyata terbaca menonjol: sisi yang menghadap cahaya lebih
   terang, sisi seberangnya lebih gelap. Cahaya diandaikan datang dari kiri
   atas, jadi sorot terangnya -1px/-1px dan bayangannya 1px/1px.

   Kenapa bukan stroke tebal biasa: garis tebal hanya terbaca sebagai garis
   tebal. Yang membuatnya terbaca sebagai tepi yang MENONJOL justru selisih
   terang-gelap di dua sisinya, dan itu bisa didapat dengan goresan tipis.

   Dua drop-shadow dalam SATU properti filter, pada SATU elemen - bukan tiap
   lingkaran diberi filter sendiri. Filter termasuk yang mahal, dan piringan
   ini satu-satunya yang perlu terbaca menonjol. */
.jalur-alas {
  opacity: .96;
  stroke: rgba(var(--hud-tepi-rgb), .55);
  stroke-width: 1.5;
  filter:
    drop-shadow(-1px -1px 0 rgba(255, 255, 255, .28))
    drop-shadow(1px 1px 0 rgba(0, 0, 0, .55));
}

/* Tepi luar kedua: goresan putus-putus yang berputar pelan berlawanan arah
   dengan cincin di dalamnya. Arah berlawanan dipilih supaya kedua cincin
   tidak terbaca menyatu jadi satu benda yang berputar.

   60 detik satu putaran - cukup lambat untuk terbaca sebagai gerak yang
   tenang, bukan hiasan yang berkedip. */
.jalur-alas-tepi {
  fill: none;
  stroke: rgba(var(--hud-sorot-rgb), .75);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-dasharray: 3 9;
  transform-origin: 200px 200px;
  animation: gerigi-putar 60s linear infinite reverse;
  filter: drop-shadow(0 0 3px rgba(var(--hud-sorot-rgb), .5));
}

@media (prefers-reduced-motion: reduce) {
  .jalur-alas-tepi { animation: none; }
}

/* Gerigi dibuat dari SATU lingkaran bergaris putus-putus, bukan puluhan
   elemen. Satu path, hasil yang sama, dan tidak ada yang perlu dihitung
   sudutnya satu per satu. */
.jalur-gerigi {
  fill: none;
  stroke: rgba(var(--hud-tepi-rgb), .38);
  stroke-width: 7;
  stroke-dasharray: 2 12;
  animation: gerigi-putar 60s linear infinite;
  transform-origin: 200px 200px;
}

@keyframes gerigi-putar { to { rotate: 360deg; } }

.inti-tepi {
  fill: none;
  stroke: rgba(var(--hud-tepi-rgb), .55);
  stroke-width: 1.5;
}

.inti-busur {
  fill: none;
  stroke: rgba(var(--hud-sorot-rgb), .5);
  stroke-width: 1.5;
  stroke-dasharray: 30 14;
  transform-origin: 200px 200px;
  animation: gerigi-putar 24s linear infinite reverse;
}

.inti-titik {
  fill: rgb(var(--hud-tepi-rgb));
  filter: drop-shadow(0 0 8px rgba(var(--hud-tepi-rgb), .9));
  animation: simpul-denyut 2.8s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .jalur-gerigi,
  .inti-busur,
  .inti-titik { animation: none; }
}

/* ==========================================================================
   KOREOGRAFI: URUTAN, BUKAN ANIMASI YANG JALAN SENDIRI-SENDIRI
   ==========================================================================
   Versi sebelumnya membuat semua elemen beranimasi terus-menerus dan saling
   bebas. Hasilnya terlihat sibuk tapi tidak menceritakan apa pun - tidak ada
   yang menunggu giliran, jadi tidak ada yang terasa sedang terjadi.

   Sekarang satu urutan: cahaya memutari USER -> berjalan ke inti -> lingkar
   menyala satu per satu -> daya mengisi SISTEM seperti baterai -> ceklis.

   Tiap tahap memakai animation-delay di dalam kelas keadaannya sendiri, jadi
   urutannya tetap benar berapa pun lama tiap tahap dipegang JS.
   ========================================================================== */

/* Beam lama dari era foto. Ia digambar dengan koordinat foto dan berhenti
   mendadak di tepi lingkaran - inilah yang terlihat "tidak nyambung". */
.energy-line,
.fx-particles { display: none; }

/* ---- 1. cahaya memutari ikon ---- */

.ikon-sapu {
  fill: none;
  stroke: rgb(var(--hud-tepi-rgb));
  stroke-width: 2.5;
  stroke-linecap: round;
  /* keliling r=30 -> 188.5. Satu goresan 40 yang berjalan mengelilinginya. */
  stroke-dasharray: 40 149;
  stroke-dashoffset: 189;
  opacity: 0;
  filter: drop-shadow(0 0 6px rgba(var(--hud-tepi-rgb), .95));
}

.ikon-sistem .ikon-sapu { stroke: rgb(var(--hud-sorot-rgb)); }

@keyframes sapu-putar {
  0% { stroke-dashoffset: 189; opacity: 0; }
  10% { opacity: 1; }
  90% { opacity: 1; }
  100% { stroke-dashoffset: -189; opacity: 0; }
}

/* USER menyala lebih dulu - ia yang memulai. */
.ai-visual.is-connecting .ikon-user .ikon-sapu {
  animation: sapu-putar 1.1s ease-in-out infinite;
}

.ai-visual.is-syncing .ikon-user .ikon-sapu {
  animation: sapu-putar .8s linear infinite;
}

/* SISTEM baru menyala di tahap verifikasi, saat giliran dayanya diisi. */
.ai-visual.is-verifying .ikon-sistem .ikon-sapu {
  animation: sapu-putar .9s linear infinite;
}

/* ---- 2. lingkar menyala satu per satu ---- */

.lingkar {
  transition: stroke .3s ease, stroke-width .3s ease;
}

@keyframes lingkar-nyala {
  0%, 100% { stroke: rgba(var(--hud-gold-rgb), .2); stroke-width: 1; }
  35%, 65% {
    stroke: rgb(var(--hud-tepi-rgb));
    stroke-width: 2.4;
    filter: drop-shadow(0 0 8px rgba(var(--hud-tepi-rgb), .8));
  }
}

/* Dari dalam ke luar: 104 -> 140 -> 176. Arah itu penting - menyala dari inti
   ke tepi terbaca sebagai daya yang menyebar keluar. Kalau dibalik, ia terbaca
   seperti sesuatu sedang menutup. */
.ai-visual.is-syncing .lingkar-1 { animation: lingkar-nyala 1.8s ease-in-out infinite; }
.ai-visual.is-syncing .lingkar-2 { animation: lingkar-nyala 1.8s ease-in-out .3s infinite; }
.ai-visual.is-syncing .lingkar-3 { animation: lingkar-nyala 1.8s ease-in-out .6s infinite; }

/* ---- 3. riak memancar dari inti ---- */

.inti-riak {
  fill: none;
  stroke: rgba(var(--hud-tepi-rgb), .7);
  stroke-width: 2;
  opacity: 0;
  transform-origin: 200px 200px;
}

@keyframes riak-pancar {
  0% { scale: 1; opacity: .85; stroke-width: 3; }
  100% { scale: 2.6; opacity: 0; stroke-width: .6; }
}

.ai-visual.is-syncing .inti-riak-1 { animation: riak-pancar 1.8s ease-out infinite; }
.ai-visual.is-syncing .inti-riak-2 { animation: riak-pancar 1.8s ease-out .9s infinite; }

/* ---- 4. daya mengisi SISTEM seperti baterai ---- */

.sistem-daya {
  fill: rgba(var(--hud-sorot-rgb), .55);
  /* Tumbuh dari DASAR ke atas: origin di bawah, scaleY dari 0. Memakai
     scale (bukan tinggi) supaya tidak memicu perhitungan tata letak ulang
     enam puluh kali per detik. */
  transform-origin: 352px 230px;
  scale: 1 0;
}

@keyframes daya-isi {
  0% { scale: 1 0; }
  100% { scale: 1 1; }
}

.ai-visual.is-verifying .sistem-daya {
  animation: daya-isi 1.6s cubic-bezier(.4, 0, .2, 1) forwards;
}

.ai-visual.is-connected .sistem-daya {
  scale: 1 1;
  fill: rgba(46, 232, 106, .6);
}

/* ---- 5. kilau melintas di permukaan piringan ---- */

.jalur-alas { transform-origin: 200px 200px; }

.ai-visual.is-syncing .jalur-alas,
.ai-visual.is-verifying .jalur-alas {
  animation: alas-denyut 2.2s ease-in-out infinite;
}

@keyframes alas-denyut {
  0%, 100% { opacity: .96; }
  50% { opacity: 1; scale: 1.012; }
}

/* ---- 6. kilatan terakhir saat terhubung ---- */

.ai-visual.is-connected .lingkar {
  stroke: rgba(46, 232, 106, .45);
  stroke-width: 1.5;
}

.ai-visual.is-connected .inti-riak-1 {
  animation: riak-pancar .9s ease-out 1;
  stroke: rgba(46, 232, 106, .9);
}

@media (prefers-reduced-motion: reduce) {
  .ikon-sapu,
  .lingkar,
  .inti-riak,
  .sistem-daya,
  .jalur-alas { animation: none !important; }

  .sistem-daya { scale: 1 1; }
}

/* --------------------------------------------------------------------------
   Cincin orbit dipindah KE LUAR cakram inti (khusus SE8).
   Lebarnya 24% menyamakannya dengan cincin pada foto lama - di dalam SVG baru,
   ukuran itu menaruh cincinnya persis DI DALAM cakram inti (r=58 dari 400).
   Border lime 4,5px dengan pendar 9px dan 22px lalu memenuhi seluruh bagian
   dalam cakram, dan teks RTP tenggelam di dalamnya.

   Diperbesar ke 44% supaya cincinnya mengorbit di luar cakram, dan pendarnya
   dipangkas: di posisi baru ia berpendar ke arah dalam, tepat ke tempat
   teksnya berada.
   -------------------------------------------------------------------------- */

.rtp-core-fx {
  width: 44%;
  top: 50%;
  transform: translate(-50%, -50%);
}

.ring-1 {
  border-width: 2.5px;
  filter: drop-shadow(0 0 5px rgba(var(--hud-tepi-rgb), .7));
}

.ring-2 {
  border-width: 2px;
  filter: drop-shadow(0 0 4px rgba(var(--hud-tepi-rgb), .55));
}

.ring-3 {
  border-width: 2.5px;
  filter: drop-shadow(0 0 6px rgba(var(--hud-sorot-rgb), .6));
}

/* Scanner ikut dimatikan: ia menyapu bidang seukuran cincin lama, dan di
   posisi baru sapuannya jatuh di tempat yang tidak berarti apa-apa. */
.scanner { display: none; }



/* ==========================================================================
   ORNAMEN HUD — busur tersegmen, kurung siku, pembidik
   ==========================================================================
   Semuanya goresan, tidak ada satu pun bidang terisi. Itu yang membedakan
   tampilan panel telemetri dari ilustrasi: bentuknya dibaca dari garis, bukan
   dari warna blok.

   Semua lingkaran memakai pathLength="360" sehingga stroke-dasharray bisa
   ditulis dalam DERAJAT. Tanpa itu, setiap jari-jari butuh angka dasharray
   sendiri yang harus dihitung ulang tiap kali ukurannya disetel.
   ========================================================================== */

.hud-busur circle { fill: none; }

/* ==========================================================================
   HIERARKI KETEBALAN
   ==========================================================================
   Sebelumnya semua cincin bergoresan 1-4px. Rentang sesempit itu membuat
   semuanya terbaca sebagai satu massa garis - tidak ada yang menonjol, jadi
   mata tidak tahu harus berhenti di mana.

   Sekarang tiga tingkat yang jelas berbeda:
     tebal   7px   cincin orbit terluar, gerigi skala
     sedang  3px   busur bergerak
     rambut  1px   lingkar diam
   Perbandingan 7:3:1 cukup jauh untuk terbaca sebagai tingkatan, bukan variasi.
   ========================================================================== */

/* Cincin orbit terluar: TEBAL, berputar, celahnya panjang. Ini pengganti
   kurung siku - bingkai yang bergerak, bukan sudut yang diam. */
.hud-orbit-tebal {
  stroke: rgb(var(--hud-tepi-rgb));
  stroke-width: 7;
  stroke-linecap: round;
  stroke-dasharray: 52 38 14 38 30 38 14 38;
  transform-origin: 200px 200px;
  animation: gerigi-putar 18s linear infinite;
  filter: drop-shadow(0 0 6px rgba(var(--hud-tepi-rgb), .6));
}

/* Lapis tipis berlawanan arah tepat di dalamnya. Dua cincin searah terbaca
   sebagai satu benda tebal; berlawanan arah barulah terbaca sebagai dua. */
.hud-orbit-tipis {
  stroke: rgba(var(--hud-sorot-rgb), .8);
  stroke-width: 2;
  stroke-dasharray: 6 22;
  transform-origin: 200px 200px;
  animation: gerigi-putar 26s linear infinite reverse;
}

/* Segmen panjang-pendek bergantian: pola khas cincin telemetri. */
.hud-segmen {
  stroke: rgba(var(--hud-tepi-rgb), .45);
  stroke-width: 1;
  stroke-dasharray: 34 6 10 6 22 6 10 6;
}

.hud-segmen-2 {
  stroke: rgba(var(--hud-sorot-rgb), .45);
  stroke-width: 2;
  stroke-dasharray: 8 4 18 10;
  transform-origin: 200px 200px;
  animation: gerigi-putar 90s linear infinite reverse;
}

/* Dua busur seperempat yang berhadapan - bukan lingkaran penuh. Bagian yang
   TIDAK digambar sama pentingnya dengan yang digambar di gaya ini. */
.hud-busur-a {
  stroke: rgb(var(--hud-tepi-rgb));
  stroke-width: 5;
  stroke-linecap: round;
  stroke-dasharray: 78 102;
  stroke-dashoffset: 39;
  transform-origin: 200px 200px;
  animation: gerigi-putar 40s linear infinite;
}

.hud-busur-b {
  stroke: rgba(var(--hud-sorot-rgb), .6);
  stroke-width: 1.5;
  stroke-dasharray: 46 134;
  transform-origin: 200px 200px;
  animation: gerigi-putar 30s linear infinite reverse;
}

.hud-jeruji path {
  fill: none;
  stroke-linecap: square;
  stroke: rgba(var(--hud-tepi-rgb), .5);
  stroke-width: 2;
}

/* ---- pembidik di dalam inti ---- */

.inti-bidik path {
  fill: none;
  stroke: rgba(var(--hud-tepi-rgb), .5);
  stroke-width: 1.5;
  stroke-linecap: round;
}

/* ---- busur progres ---- */

.inti-progres {
  fill: none;
  stroke: rgb(var(--hud-tepi-rgb));
  stroke-width: 3;
  stroke-linecap: round;
  stroke-dasharray: 0 360;
  /* Mulai dari puncak, bukan dari sisi kanan - arah yang dibaca orang sebagai
     "nol" pada indikator melingkar. */
  transform: rotate(-90deg);
  transform-origin: 200px 200px;
  filter: drop-shadow(0 0 6px rgba(var(--hud-tepi-rgb), .8));
  opacity: 0;
}

@keyframes progres-isi {
  from { stroke-dasharray: 0 360; opacity: 1; }
  to { stroke-dasharray: 360 0; opacity: 1; }
}

.ai-visual.is-connecting .inti-progres { animation: progres-isi 1.2s ease-out forwards; }
.ai-visual.is-syncing .inti-progres { animation: progres-isi 1.6s ease-in-out forwards; }
.ai-visual.is-verifying .inti-progres { animation: progres-isi 1.4s ease-in forwards; }

.ai-visual.is-connected .inti-progres {
  stroke-dasharray: 360 0;
  stroke: rgba(46, 232, 106, .9);
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .hud-segmen-2,
  .hud-busur-a,
  .hud-busur-b,
  .inti-progres { animation: none; }
}

/* --------------------------------------------------------------------------
   Gulungan provider dipindah ke BAWAH bidang animasi (berlaku di semua WLB).
   Posisi lamanya bottom: calc(7% + 54px) disetel untuk foto - di sana bagian
   bawah gambar memang gelap dan kosong. Piringan HUD mengisi hampir seluruh
   kotak, jadi di titik yang sama gulungannya menimpa busur dan pembidik.

   Diturunkan ke -44px: keluar dari lingkaran sepenuhnya, di ruang kosong
   bawahnya. .ai-visual dibuat overflow: visible supaya bagian yang
   menggantung itu tidak terpotong.
   -------------------------------------------------------------------------- */

/* [data-design="mnj"] DITULIS DUA KALI dengan sengaja - bukan salah ketik.
   Aturan dasarnya ada di mnj-design.css yang dimuat SETELAH berkas ini
   dengan spesifisitas sama (0,2,0) kalau atributnya cuma ditulis sekali;
   pada dasi begitu, urutan berkas yang menentukan dan mnj-design.css akan
   menang. Mengulang atribut yang sama menaikkan spesifisitas ke (0,3,0)
   tanpa perlu menyebut tema tertentu - jadi override ini tetap menang di
   ketiga WLB, bukan cuma satu. */
[data-design="mnj"][data-design="mnj"] .ai-visual { overflow: visible; }

[data-design="mnj"][data-design="mnj"] .provider-reel {
  bottom: -44px;
  padding: 0;
}

/* Diberi alas sendiri supaya tetap terbaca di atas latar halaman yang ramai -
   di posisi lama ia menumpang gelapnya foto, sekarang tidak ada lagi. */
[data-design="mnj"][data-design="mnj"] .provider-reel__window {
  border: 1px solid rgba(var(--hud-tepi-rgb), .4);
  border-radius: 8px;
  background: rgba(10, 5, 22, .8);
}

/* Lencana SISTEM TERHUBUNG dulu duduk di bottom: 7% - di dalam piringan.
   Ikut dinaikkan ke tepi bawah lingkaran supaya tidak menutupi pembidik. */
[data-design="mnj"][data-design="mnj"] .connected-status {
  bottom: 2%;
}

/* ==========================================================================
   DESKTOP: DISEJAJARKAN DENGAN KARTU FORM, DIPERBESAR, DAN LEBIH CERAH
   ==========================================================================
   Sebelumnya visual berada di 227-687 sementara kartu form di 382-783 - meleset
   155px ke atas. Penyebabnya align-items: start pada .hero-grid: visual sejajar
   dengan puncak BARIS, dan puncak baris itu judul, bukan kartunya.

   Dipakai align-self: end, bukan margin-top sekian piksel. Tinggi judul berubah
   mengikuti lebar layar dan panjang teksnya; angka tetap akan meleset lagi
   begitu salah satunya berubah. Menyejajarkan ke DASAR memberi titik yang
   pasti tanpa perlu tahu tinggi apa pun di atasnya.
   ========================================================================== */

@media (min-width: 1025px) {
  [data-design="mnj"][data-design="mnj"] .hero-grid {
    /* Kolom kanan diperlebar dari .93fr ke 1.02fr. */
    grid-template-columns: minmax(0, 1fr) minmax(420px, 1.02fr);
    align-items: end;
  }

  [data-design="mnj"][data-design="mnj"] .ai-visual {
    align-self: end;
    /* Ruang untuk gulungan provider yang menggantung 44px di bawahnya. */
    margin-bottom: 52px;
  }
}

/* ---- lebih cerah saat sistem belum jalan ----
   Keadaan diam dulu paling redup, padahal justru saat itulah orang pertama
   kali melihatnya dan belum tahu benda ini apa. Yang redup seharusnya keadaan
   SESUDAH selesai, bukan sebelum mulai. */

.jalur-l1 {
  opacity: 1;
  filter: none;
}

.jalur-l2 { opacity: 1; }

.ai-visual.is-idle .jalur-utama path {
  stroke: rgba(var(--hud-tepi-rgb), .62);
}

.ai-visual.is-idle .lingkar {
  stroke: rgba(var(--hud-tepi-rgb), .34);
}

.ai-visual.is-idle .hud-segmen {
  stroke: rgba(var(--hud-tepi-rgb), .8);
}

.ai-visual.is-idle .hud-jeruji path {
  fill: none;
  stroke-linecap: square;
  stroke: rgba(var(--hud-tepi-rgb), .85);
}

.ai-visual.is-idle .inti-teks {
  filter: drop-shadow(0 0 12px rgba(var(--hud-tepi-rgb), .9));
}

/* Paket tetap berjalan pelan saat diam - itu yang memberi tahu bahwa sistemnya
   hidup dan menunggu, bukan gambar mati. */
.ai-visual.is-idle .jalur-paket use {
  opacity: .8;
}

/* ---- pad di belokan ---- */

.jalur-pad circle {
  fill: rgba(var(--hud-tepi-rgb), .85);
}

/* ---- cincin ikon: lebih tebal dan berlapis ---- */

.ikon-cincin-luar {
  fill: none;
  stroke: rgba(var(--hud-tepi-rgb), .5);
  stroke-width: 2;
  /* Tersegmen, bukan utuh: empat busur panjang diselingi celah pendek. Cincin
     penuh terbaca sebagai batas; cincin tersegmen terbaca sebagai indikator. */
  stroke-dasharray: 70 20;
  transform-origin: 48px 200px;
  animation: gerigi-putar 26s linear infinite;
}

.ikon-sistem .ikon-cincin-luar {
  stroke: rgba(var(--hud-sorot-rgb), .5);
  transform-origin: 352px 200px;
  animation-direction: reverse;
}

/* Cincin dalam dipertebal 1,5px -> 3px sesuai permintaan. */
.ikon-alas {
  stroke-width: 3;
}

/* Sapuan cahaya ikut dipertebal supaya sebanding dengan cincinnya. */
.ikon-sapu {
  stroke-width: 3.5;
}

/* ---- batang utama, cabang, pad kotak ---- */

/* Batang jauh lebih tebal dari pengumpannya. Kalau semua sama tebal, susunan
   bus-nya hilang dan kembali terbaca sebagai beberapa garis sejajar. */
.jalur-batang {
  stroke-width: 5 !important;
  stroke: rgba(var(--hud-tepi-rgb), .75) !important;
}

.jalur-cabang path {
  fill: none;
  stroke: rgba(var(--hud-tepi-rgb), .6);
  stroke-width: 2;
  stroke-linecap: butt;
}

.jalur-pad rect {
  fill: rgba(var(--hud-tepi-rgb), .9);
}

/* ==========================================================================
   DESKTOP: DIPUSATKAN
   ==========================================================================
   Sebelumnya visual di 137-726 sementara baris isinya 131-784: celah 6px di
   atas tapi 58px di bawah, dan tepi kanannya menempel persis ke batas grid.
   Terbaca miring ke kanan-atas.
   ========================================================================== */

@media (min-width: 1025px) {
  [data-design="mnj"][data-design="mnj"] .hero-grid {
    grid-template-columns: minmax(0, 1fr) minmax(400px, .96fr);
    align-items: center;
  }

  [data-design="mnj"][data-design="mnj"] .ai-visual {
    align-self: center;
    /* Bukan align-self: end lagi. Menyejajarkan ke dasar membuat celah atas dan
       bawah jauh berbeda; dipusatkan membuat keduanya sama. */
    margin-bottom: 0;
    /* Napas dari tepi kanan grid supaya piringannya tidak menempel batas. */
    margin-right: 12px;
  }
}

/* ==========================================================================
   SE8: BORDER LIME
   ==========================================================================
   Tema ini memakai ungu sebagai warna dominan dan lime sebagai aksen. Untuk
   GARIS, ungu adalah pilihan yang buruk: bidang di belakangnya juga ungu, jadi
   tepinya melebur. Lime memberi batas yang benar-benar terbaca.
   ========================================================================== */

[data-design="mnj"][data-design="mnj"] .modal .modal-content,
[data-design="mnj"][data-design="mnj"] .game-modal .modal-content,
[data-design="mnj"][data-design="mnj"] .selected-game,
[data-design="mnj"][data-design="mnj"] .engine-result,
[data-design="mnj"][data-design="mnj"] .game-card {
  border-color: rgba(var(--hud-tepi-rgb), .45);
}

[data-design="mnj"][data-design="mnj"] .field input,
[data-design="mnj"][data-design="mnj"] .field select,
[data-design="mnj"][data-design="mnj"] .modal input,
[data-design="mnj"][data-design="mnj"] .modal select {
  border-color: rgba(var(--hud-tepi-rgb), .4);
}

[data-design="mnj"][data-design="mnj"] .field input:focus,
[data-design="mnj"][data-design="mnj"] .modal input:focus {
  border-color: rgb(var(--hud-tepi-rgb));
  box-shadow: 0 0 0 3px rgba(var(--hud-tepi-rgb), .18);
}

/* Bar persentase di modal: alur dan tepinya ikut lime, tapi ISIAN-nya tetap
   memakai nada merah/kuning/hijau bawaan. Warna isian itu menyampaikan MAKNA -
   tinggi rendahnya persentase - dan menyeragamkannya jadi lime akan
   menghapus satu-satunya informasi yang dibawa bar ini. */
[data-design="mnj"][data-design="mnj"] .selected-game__bar .game-percentage__track {
  border-color: rgba(var(--hud-tepi-rgb), .35);
}

.selected-game__bar {
  margin-top: 8px;
  max-width: 220px;
}
