/* ============================================================
   PORTAL SISTEM INFORMASI TERINTEGRASI — PERUMDA AIR MINUM
   DUASUDARA BITUNG
   ============================================================ */

:root{
  --navy-950:#050d18;
  --navy-900:#0A2540;
  --navy-800:#0e3050;
  --navy-700:#123a63;
  --blue-500:#2196F3;
  --cyan-400:#00E5FF;
  --teal-300:#64FFDA;
  --ink-100:#eaf4ff;
  --ink-300:#a9c2de;
  --ink-400:#7d97b8;
  --green-500:#22c55e;
  --green-300:#6ee7a3;

  --glass-bg:rgba(255,255,255,.06);
  --glass-bg-strong:rgba(255,255,255,.10);
  --glass-border:rgba(255,255,255,.16);
  --glass-border-hover:rgba(100,255,218,.55);

  --font-display:'Poppins',ui-sans-serif,system-ui,sans-serif;
  --font-body:'Inter',ui-sans-serif,system-ui,sans-serif;

  /* dual-ring orbit: inner = 4 sistem inti, outer = 5 sistem operasional/pengawasan.
     Radius orbit TIDAK ditetapkan di sini — dihitung di orbit.js dari ruang nyata
     yang tersedia (elips, mengikuti layar lanskap), lalu di-clamp agar tidak pernah
     keluar viewport maupun menabrak logo tengah. */
  --card-w:226px;
  --card-h:118px;   /* tinggi MINIMUM; tinggi nyata diukur ulang di orbit.js */
  --icon-size:33px;
  --logo-size:216px;

  /* Lama satu putaran penuh. Makin BESAR angkanya, makin LAMBAT rotasinya.
     28s → 38s (2026-09-16, permintaan Frits: pelankan sedikit). */
  --orbit-duration:38s;
}

*,*::before,*::after{box-sizing:border-box}
html,body{height:100%}
/* Kolom flex setinggi layar: header & footer memakai tinggi alaminya, sisanya
   diberikan ke .hero. Sebelumnya tinggi hero dihitung manual (100dvh dikurangi
   angka tetap), dan angka itu meleset beberapa piksel dari tinggi header+footer
   yang sebenarnya — halaman jadi sedikit lebih tinggi dari layar sehingga
   header tampak terpotong di atas. */
body{
  margin:0;
  min-height:100dvh;
  display:flex;
  flex-direction:column;
  font-family:var(--font-body);
  color:var(--ink-100);
  background:var(--navy-950);
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
img{max-width:100%;display:block}
button{font:inherit}
a{color:inherit}
::selection{background:rgba(0,229,255,.35);color:#fff}

/* ---------------------------------------------------------
   BACKGROUND — gradient, glow blobs, particles, ripple
--------------------------------------------------------- */
.bg-layer{
  position:fixed;
  inset:0;
  z-index:0;
  overflow:hidden;
  pointer-events:none;
}
.bg-gradient{
  position:absolute;
  inset:0;
  background:
    radial-gradient(1100px 700px at 18% 8%, rgba(33,150,243,.22), transparent 60%),
    radial-gradient(900px 650px at 85% 18%, rgba(0,229,255,.14), transparent 55%),
    radial-gradient(1200px 900px at 50% 100%, rgba(100,255,218,.10), transparent 60%),
    linear-gradient(160deg, var(--navy-950) 0%, var(--navy-900) 45%, #0b2038 75%, var(--navy-950) 100%);
}
.bg-grid{
  position:absolute;
  inset:-2px;
  background-image:
    linear-gradient(rgba(120,180,255,.06) 1px, transparent 1px),
    linear-gradient(90deg, rgba(120,180,255,.06) 1px, transparent 1px);
  background-size:46px 46px;
  mask-image:radial-gradient(ellipse 75% 65% at 50% 45%, #000 40%, transparent 78%);
  -webkit-mask-image:radial-gradient(ellipse 75% 65% at 50% 45%, #000 40%, transparent 78%);
}

#particle-canvas{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  opacity:0;
  transition:opacity 1.6s ease;
}
body.is-ready #particle-canvas{opacity:.85}

.glow-blob{
  position:absolute;
  border-radius:50%;
  filter:blur(70px);
  opacity:0;
  transition:opacity 1.8s ease 200ms;
  will-change:transform;
}
body.is-ready .glow-blob{opacity:1}
.glow-blob--a{
  width:520px;height:520px; left:-120px; top:-140px;
  background:radial-gradient(circle at 35% 35%, rgba(33,150,243,.55), transparent 70%);
  animation:driftA 22s ease-in-out infinite;
}
.glow-blob--b{
  width:620px;height:620px; right:-180px; top:10%;
  background:radial-gradient(circle at 60% 40%, rgba(0,229,255,.4), transparent 70%);
  animation:driftB 26s ease-in-out infinite;
}
.glow-blob--c{
  width:560px;height:560px; left:50%; bottom:-260px; transform:translateX(-50%);
  background:radial-gradient(circle at 50% 50%, rgba(100,255,218,.32), transparent 70%);
  animation:driftC 30s ease-in-out infinite;
}
@keyframes driftA{
  0%,100%{transform:translate(0,0) scale(1)}
  50%{transform:translate(60px,40px) scale(1.12)}
}
@keyframes driftB{
  0%,100%{transform:translate(0,0) scale(1)}
  50%{transform:translate(-50px,50px) scale(1.08)}
}
@keyframes driftC{
  0%,100%{transform:translate(-50%,0) scale(1)}
  50%{transform:translate(calc(-50% + 40px),-30px) scale(1.1)}
}

/* Riak air — dipancarkan dari titik pusat orbit (= pusat logo).
   left/top 50% di sini mengacu ke .orbit-system, bukan ke layar, jadi
   posisinya otomatis ikut logo di ukuran layar mana pun. */
.ripple-wrap{
  position:absolute;
  left:50%; top:50%;
  width:0; height:0;
  transform:translate(-50%,-50%);
  pointer-events:none;
  z-index:1;   /* di belakang cincin orbit, logo (z-5), dan kartu (z-4) */
}
/* Di mode grid logo pindah ke atas dan .orbit-system tidak lagi jadi
   panggung melingkar, sehingga titik tengahnya tidak lagi berimpit dengan
   logo — riak disembunyikan daripada memancar dari tempat yang salah. */
.orbit-system:has(.orbit.is-grid) .ripple-wrap,
body.grid-mode .ripple-wrap{display:none}
.ripple{
  position:absolute;
  left:0; top:0;
  width:120px;height:120px;
  margin:-60px 0 0 -60px;
  border-radius:50%;
  border:1px solid rgba(100,255,218,.35);
  opacity:0;
  animation:rippleOut 6.5s ease-out infinite;
}
.ripple:nth-child(2){animation-delay:2.15s}
.ripple:nth-child(3){animation-delay:4.3s}
@keyframes rippleOut{
  0%{opacity:0; transform:scale(.3)}
  12%{opacity:.55}
  100%{opacity:0; transform:scale(6.2)}
}

/* floating bubbles */
.bubbles{position:absolute; inset:0; overflow:hidden}
.bubble{
  position:absolute;
  bottom:-10%;
  border-radius:50%;
  background:radial-gradient(circle at 32% 28%, rgba(255,255,255,.55), rgba(100,255,218,.05) 70%);
  border:1px solid rgba(180,230,255,.25);
  opacity:0;
  animation-name:floatUp;
  animation-timing-function:ease-in;
  animation-iteration-count:infinite;
}
@keyframes floatUp{
  0%{opacity:0; transform:translateY(0) translateX(0) scale(.8)}
  8%{opacity:.5}
  92%{opacity:.35}
  100%{opacity:0; transform:translateY(-115vh) translateX(var(--drift,30px)) scale(1.05)}
}

/* ---------------------------------------------------------
   HEADER
--------------------------------------------------------- */
.site-header{
  position:relative;
  z-index:20;
  display:flex;
  align-items:center;
  gap:14px;
  max-width:1180px;
  margin:0 auto;
  padding:18px 24px;
  opacity:0;
}
.site-header .h-logo{
  width:42px; height:42px; object-fit:contain;
  filter:drop-shadow(0 0 10px rgba(0,229,255,.35));
}
.site-header .h-text{line-height:1.25}
.site-header .h-title{
  font-family:var(--font-display);
  font-weight:700;
  font-size:14.5px;
  letter-spacing:.2px;
  color:var(--ink-100);
}
.site-header .h-sub{
  font-size:12px;
  color:var(--ink-400);
  letter-spacing:.2px;
}

/* ---------------------------------------------------------
   HERO / ORBIT SYSTEM
--------------------------------------------------------- */
.hero{
  position:relative;
  z-index:10;
  flex:1 1 auto;
  /* Lantai tinggi dibuat rendah. Dulu 520px — angka itu memaksa halaman lebih
     tinggi dari layar (muncul scrollbar) di jendela pendek. Sekarang orbit
     sudah bisa mengecil sendiri mengikuti ruang yang ada, jadi lantai setinggi
     itu tidak lagi dibutuhkan. */
  min-height:280px;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:14px 16px;
}
.orbit-system{
  position:relative;
  width:100%;
  height:100%;
  max-width:1560px;
  display:flex;
  align-items:center;
  justify-content:center;
}

/* orbit guide ellipses — sized by orbit.js to match the real computed radii exactly */
.orbit-ring{
  position:absolute;
  left:50%; top:50%;
  width:0; height:0;
  border-radius:50%;
  transform:translate(-50%,-50%);
  pointer-events:none;
  opacity:0;
  transition:opacity 1.4s ease 300ms;
}
body.is-ready .orbit-ring{opacity:1}
.orbit-ring--main{
  border:1px solid rgba(120,200,255,.22);
  box-shadow:0 0 26px rgba(0,229,255,.10), inset 0 0 26px rgba(0,229,255,.06);
}
.orbit-ring--inner{
  border:1px dashed rgba(120,200,255,.2);
}

/* center glass logo.
   Dipusatkan dengan inset:0 + margin:auto, BUKAN left/top 50% + translate(-50%,-50%).
   Alasannya: `transform` pada elemen ini dikuasai GSAP (animasi zoom saat masuk)
   dan ukurannya diubah JS saat orbit menyusut. Selama pemusatan ikut menumpang
   di `transform`, setiap kali transform itu tertimpa, kosong, atau tertinggal di
   ukuran lama, logo langsung melenceng tepat setengah ukurannya ke kanan-bawah.
   Dengan margin:auto, pemusatan ditangani model kotak dan SELALU mengikuti ukuran
   terkini — transform bebas dipakai murni untuk animasi skala. */
.center-logo{
  position:absolute;
  inset:0;
  margin:auto;
  transform:scale(.4);
  width:var(--logo-size);
  height:var(--logo-size);
  border-radius:50%;
  display:flex;
  align-items:center;
  justify-content:center;
  background:
    radial-gradient(circle at 32% 28%, rgba(255,255,255,.14), rgba(255,255,255,.02) 60%),
    var(--glass-bg);
  border:1px solid var(--glass-border);
  backdrop-filter:blur(18px);
  -webkit-backdrop-filter:blur(18px);
  box-shadow:
    0 0 0 1px rgba(0,229,255,.08),
    0 0 60px rgba(33,150,243,.35),
    0 0 120px rgba(0,229,255,.18),
    inset 0 1px 0 rgba(255,255,255,.25),
    inset 0 -18px 40px rgba(0,0,0,.25);
  opacity:0;
  z-index:5;
}
.center-logo::before,
.center-logo::after{
  content:'';
  position:absolute;
  inset:-14px;
  border-radius:50%;
  border:1px solid rgba(100,255,218,.28);
  animation:pulseRing 3.6s ease-out infinite;
}
.center-logo::after{animation-delay:1.8s}
@keyframes pulseRing{
  0%{transform:scale(.88); opacity:.65}
  100%{transform:scale(1.18); opacity:0}
}
.center-logo img{
  width:64%;
  height:64%;
  object-fit:contain;
  filter:drop-shadow(0 4px 18px rgba(0,0,0,.35));
}

/* orbit — posisi kartu ditulis per-frame oleh orbit.js (jalur elips), sehingga
   kartu tegak lurus dengan sendirinya; tidak perlu counter-rotation. */
.orbit{
  position:absolute;
  inset:0;
  z-index:4;
}
/* Tinggi slot dibiarkan AUTO (mengikuti isi kartu), dan pemusatan dilakukan
   lewat translate(-50%,-50%) di dalam transform yang ditulis orbit.js — bukan
   negative-margin berbasis --card-h. Sebelumnya kartu tumbuh melebihi tinggi
   slot yang ditetapkan, sehingga hitungan jarak antar-orbit meleset dan kartu
   dua ring bisa bertabrakan walau perhitungannya "aman". */
.orbit-slot{
  position:absolute;
  left:50%; top:50%;
  width:var(--card-w);
  transform:translate(-50%,-50%);
  opacity:0;
  will-change:transform;
}

/* ---------------------------------------------------------
   MODULE CARD (glassmorphism)
--------------------------------------------------------- */
.module-card{
  position:relative;
  width:100%;
  min-height:var(--card-h);
  border-radius:18px;
  padding:9px 12px;
  display:flex;
  flex-direction:column;
  justify-content:space-between;
  gap:4px;
  background:linear-gradient(155deg, var(--glass-bg-strong), rgba(255,255,255,.03));
  border:1px solid var(--glass-border);
  backdrop-filter:blur(16px);
  -webkit-backdrop-filter:blur(16px);
  box-shadow:0 10px 30px rgba(2,10,25,.45), inset 0 1px 0 rgba(255,255,255,.12);
  transition:transform .35s cubic-bezier(.2,.9,.25,1), box-shadow .35s ease, border-color .35s ease, background .35s ease;
  overflow:hidden;
}
.module-card::before{
  content:'';
  position:absolute; inset:0;
  background:linear-gradient(120deg, transparent 30%, rgba(0,229,255,.12) 48%, transparent 66%);
  transform:translateX(-120%);
  transition:transform .7s ease;
  pointer-events:none;
}
.orbit-slot:hover .module-card{
  transform:translateY(-6px) scale(1.045);
  border-color:var(--glass-border-hover);
  box-shadow:0 20px 46px rgba(2,10,25,.55), 0 0 0 1px rgba(100,255,218,.25), 0 0 34px rgba(0,229,255,.28), inset 0 1px 0 rgba(255,255,255,.18);
  background:linear-gradient(155deg, rgba(255,255,255,.14), rgba(255,255,255,.05));
}
.orbit-slot:hover .module-card::before{transform:translateX(120%)}

.mc-top{display:flex; align-items:flex-start; justify-content:space-between; gap:8px; flex-shrink:0}
.mc-icon{
  width:var(--icon-size); height:var(--icon-size);
  border-radius:12px;
  display:flex; align-items:center; justify-content:center;
  font-size:calc(var(--icon-size) * 0.5);
  background:linear-gradient(145deg, rgba(33,150,243,.35), rgba(0,229,255,.12));
  border:1px solid rgba(140,210,255,.35);
  transition:transform .4s cubic-bezier(.2,.9,.25,1), background .3s ease;
  flex:none;
}
.orbit-slot:hover .mc-icon{
  transform:rotate(-8deg) scale(1.12);
  background:linear-gradient(145deg, rgba(0,229,255,.5), rgba(100,255,218,.25));
}
.mc-status{
  display:inline-flex; align-items:center; gap:5px;
  font-size:11px; font-weight:600; letter-spacing:.4px;
  color:var(--green-300);
  padding:4px 9px 4px 7px;
  border-radius:999px;
  background:rgba(34,197,94,.12);
  border:1px solid rgba(34,197,94,.35);
  white-space:nowrap;
}
.mc-status .dot{
  width:6px; height:6px; border-radius:50%;
  background:var(--green-500);
  box-shadow:0 0 0 0 rgba(34,197,94,.6);
  animation:statusPulse 1.8s ease-out infinite;
}
@keyframes statusPulse{
  0%{box-shadow:0 0 0 0 rgba(34,197,94,.55)}
  70%{box-shadow:0 0 0 6px rgba(34,197,94,0)}
  100%{box-shadow:0 0 0 0 rgba(34,197,94,0)}
}
.mc-title{
  font-family:var(--font-display);
  font-weight:600;
  font-size:13px;
  line-height:1.25;
  color:var(--ink-100);
  display:-webkit-box;
  -webkit-line-clamp:2;
  -webkit-box-orient:vertical;
  overflow:hidden;
  flex-shrink:0;
  min-height:calc(1.3em * 2);
}
.mc-btn{
  align-self:flex-start;
  flex-shrink:0;
  position:relative;
  overflow:hidden;
  display:inline-flex;
  align-items:center;
  gap:6px;
  font-family:var(--font-body);
  font-weight:600;
  font-size:12.5px;
  line-height:1.15;
  color:#04121f;
  background:linear-gradient(120deg, var(--teal-300), var(--cyan-400) 55%, var(--blue-500));
  border:none;
  border-radius:10px;
  padding:6px 13px;
  cursor:pointer;
  box-shadow:0 6px 16px rgba(0,229,255,.28);
  transition:transform .2s ease, box-shadow .2s ease, filter .2s ease;
}
.mc-btn:hover{transform:translateY(-2px); box-shadow:0 10px 22px rgba(0,229,255,.4); filter:brightness(1.05)}
.mc-btn:active{transform:translateY(0)}
.mc-btn:focus-visible{outline:2px solid var(--teal-300); outline-offset:3px}
.orbit-slot:focus-within .module-card{
  border-color:var(--glass-border-hover);
  box-shadow:0 20px 46px rgba(2,10,25,.55), 0 0 0 1px rgba(100,255,218,.25), 0 0 34px rgba(0,229,255,.28);
}
.mc-btn svg{width:13px; height:13px; transition:transform .25s ease}
.orbit-slot:hover .mc-btn svg{transform:translateX(3px)}
.mc-btn .spinner{
  display:none;
  width:13px; height:13px;
  border-radius:50%;
  border:2px solid rgba(4,18,31,.35);
  border-top-color:#04121f;
  animation:spin .7s linear infinite;
}
.mc-btn.is-loading .btn-label,
.mc-btn.is-loading svg.arrow{display:none}
.mc-btn.is-loading .spinner{display:inline-block}
@keyframes spin{to{transform:rotate(360deg)}}

.module-card.status-maint .mc-status{color:#fbbf24; background:rgba(251,191,36,.12); border-color:rgba(251,191,36,.35)}
.module-card.status-maint .mc-status .dot{background:#fbbf24; animation:none}
.module-card.status-off .mc-status{color:#f87171; background:rgba(248,113,113,.12); border-color:rgba(248,113,113,.35)}
.module-card.status-off .mc-status .dot{background:#f87171; animation:none; box-shadow:none}

.mc-ripple{
  position:absolute;
  border-radius:50%;
  background:rgba(255,255,255,.55);
  transform:scale(0);
  animation:mcRipple .6s ease-out forwards;
  pointer-events:none;
}
@keyframes mcRipple{to{transform:scale(1); opacity:0}}

/* ---------------------------------------------------------
   FOOTER
--------------------------------------------------------- */
.site-footer{
  position:relative;
  z-index:20;
  text-align:center;
  padding:22px 16px 26px;
  color:var(--ink-400);
  font-size:12px;
  line-height:1.8;
  opacity:0;
}
.site-footer strong{color:var(--ink-300); font-weight:600}
.site-footer .ver{
  display:inline-block;
  margin-top:2px;
  font-size:11px;
  letter-spacing:.3px;
  color:rgba(100,255,218,.75);
}

/* ---------------------------------------------------------
   RESPONSIVE
   Orbit (10 kartu) butuh ruang lebar untuk tetap terbaca, jadi ambang
   orbit->grid kini 1280px. Riwayatnya: 640px (versi 4 modul) → 1024px
   (versi 9 modul) → 1280px (versi 10 modul, karena di 1024 semua judul
   terpotong dan tombol tinggal 20px). Perangkat SENTUH selalu grid
   berapa pun lebarnya — lihat `(pointer: fine)` di orbit.js.
--------------------------------------------------------- */
/* Ukuran penuh hanya untuk layar besar. Di bawahnya kartu & logo mengecil
   bertahap — bukan sekadar demi estetika: radius orbit dihitung dari sisa
   ruang setelah dikurangi ukuran kartu, jadi kartu yang terlalu besar di
   layar sedang justru MENYEMPITKAN orbit sampai audit geometri gagal dan
   tampilan turun ke grid. Nilai di bawah sudah diuji lolos audit. */
@media (max-width:1599px) and (min-width:1280px){
  :root{ --card-w:198px; --card-h:108px; --icon-size:30px; --logo-size:180px; }
  .mc-title{font-size:12.5px}
  .mc-btn{font-size:12px; padding:5px 12px}
}
/* 1024-1279px kini SELALU mode grid (bukan orbit lagi). Nilai di sini hanya
   memengaruhi ukuran logo & ikon di tampilan grid. */
@media (max-width:1279px) and (min-width:1024px){
  :root{ --icon-size:30px; --logo-size:158px; }
  .mc-title{font-size:12.5px}
}

/* MODE GRID — berlaku di LEBAR BERAPA PUN, bukan hanya layar kecil.
   orbit.js bisa menyalakan .is-grid di layar lebar juga (kalau audit geometri
   menyatakan kartu bakal bertabrakan), jadi aturan grid ini TIDAK BOLEH
   dikurung di dalam media query layar kecil — dulu begitu, akibatnya di
   jendela yang gagal audit semua kartu menumpuk di tengah menutupi logo. */
.orbit.is-grid{
  position:relative;
  inset:auto;
  display:grid;
  grid-template-columns:repeat(3, 1fr);
  gap:14px;
  padding:0 2px;
  width:100%;
}
.orbit.is-grid .orbit-slot{
  position:relative;
  left:auto; top:auto;
  width:auto; height:auto;
  margin:0;
  transform:none !important;
}
.orbit.is-grid .module-card{min-height:172px; border-radius:18px; padding:12px}
/* Di mode grid kartunya lebih tinggi dan ruangnya menganggur, jadi judul
   panjang tidak perlu dipangkas jadi 2 baris seperti di orbit. */
.orbit.is-grid .mc-title{
  -webkit-line-clamp:3;
  min-height:calc(1.26em * 3);
}
/* Saat grid aktif, sistem orbit berhenti jadi panggung melingkar: logo naik
   ke atas sebagai judul, cincin panduan disembunyikan, tinggi mengikuti isi. */
.orbit-system:has(.orbit.is-grid),
body.grid-mode .orbit-system{
  display:block;
  height:auto;
  max-height:none;
}
.orbit-system:has(.orbit.is-grid) .orbit-ring,
body.grid-mode .orbit-ring{display:none}
.orbit-system:has(.orbit.is-grid) .center-logo,
body.grid-mode .center-logo{
  position:relative;
  inset:auto;
  transform:none;
  margin:0 auto 28px;
}
/* Lihat catatan di markGridMode() (orbit.js): memutus lingkaran
   scrollbar-muncul → layout-ulang → scrollbar-hilang → berulang. */
body.orbit-mode{ overflow-y:hidden; }

.hero:has(.orbit.is-grid),
body.grid-mode .hero{
  flex:0 0 auto;
  min-height:0;
  align-items:flex-start;
}

/* TABLET + MOBILE: selalu grid (orbit tidak pernah dicoba di bawah 1280px) */
@media (max-width:1279px){
  :root{ --logo-size:140px; }
  .hero{flex:0 0 auto; min-height:0; padding:20px 16px 6px}
  .orbit-system{
    width:100%; height:auto; max-height:none;
    display:block;
  }
  .orbit-ring{display:none}
  .center-logo{
    position:relative;
    inset:auto;
    transform:none;
    margin:0 auto 28px;
  }
  .orbit{position:relative; inset:auto}
  .mc-title{font-size:12.5px}
  .site-header .h-title{font-size:13px}
}
@media (max-width:640px){
  .site-header{padding:14px 16px; gap:10px}
  .site-header .h-title{font-size:12.5px}
  .site-header .h-sub{font-size:10.5px}
}
@media (max-width:479px){
  .orbit.is-grid{grid-template-columns:repeat(2, 1fr)}
  .mc-title{font-size:12px}
}

/* ---------------------------------------------------------
   REDUCED MOTION
--------------------------------------------------------- */
@media (prefers-reduced-motion: reduce){
  .glow-blob, .ripple, .bubble, .center-logo::before, .center-logo::after, .mc-status .dot{
    animation:none !important;
  }
  .module-card, .mc-icon, .mc-btn{transition:none !important}
}
body.reduce-motion .orbit{animation:none !important}
