/* BERKAS INI HASIL GENERATE — jangan disunting.
   Dijahit oleh tools/build.js dari: assets/css/tokens.css, assets/css/base.css, assets/css/layout.css, assets/css/components.css, assets/css/sections.css, assets/css/media.css.
   Sunting berkas sumbernya, lalu jalankan node tools/build.js. */

/* ===== assets/css/tokens.css ===== */
/* ==========================================================================
   Barokah Energy — Design Tokens
   Palet diturunkan langsung dari gradien logo resmi:
   biru #072CBD → #30B3FF (teknologi, keandalan)
   surya #FB7806 → #FFD100 (energi, matahari)
   ========================================================================== */

/* --------------------------------------------------------------------------
   Font web — dilayani dari domain sendiri, bukan dari Google.

   Sebelumnya tiga keluarga ini dimuat lewat <link> ke fonts.googleapis.com,
   yang berarti setiap kunjungan menunggu DNS, TLS, dan sebuah stylesheet
   penghalang render di dua domain pihak ketiga sebelum satu huruf pun
   tergambar. Berkasnya kini ikut di repo dan dilayani dari origin yang sama,
   sehingga koneksinya sudah terbuka sejak permintaan HTML pertama.

   Berkas yang dipakai adalah woff2 subset `latin` yang persis sama dengan
   yang dikirim Google, bukan hasil enkode ulang, agar tampilannya tidak
   bergeser sedikit pun — termasuk metrik yang menjadi dasar muka cadangan
   di bawah.

   Subset lain (latin-ext, cyrillic, greek, vietnamese) sengaja tidak diambil.
   Seluruh naskah situs ini hanya memakai 19 karakter non-ASCII dan semuanya
   ada di dalam subset latin, kecuali ₂ ₄ → ≈ ≥ yang memang sudah jatuh ke
   font sistem sejak dulu karena Google pun tidak memuatnya di subset latin.

   Plus Jakarta Sans adalah satu berkas variabel: empat bobot di bawah
   menunjuk ke berkas yang sama dan hanya berbeda titik pada sumbu wght.
   Source Serif 4 juga variabel dan menyertakan sumbu opsz, yang membuatnya
   52 KB alih-alih 22 KB. Sumbu itu dipertahankan karena `font-optical-sizing`
   aktif secara bawaan: menghapusnya akan menipiskan goresan judul.

   Bila berkasnya diperbarui, ganti juga nama berkasnya. Cache-nya satu tahun
   dan `immutable` (.htaccess), jadi nama yang sama tidak akan pernah diambil
   ulang. -------------------------------------------------------------------- */

@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../font/plus-jakarta-sans-v12-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../font/plus-jakarta-sans-v12-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../font/plus-jakarta-sans-v12-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('../font/plus-jakarta-sans-v12-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../font/source-serif-4-v14-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../font/ibm-plex-mono-v20-latin-400.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../font/ibm-plex-mono-v20-latin-500.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../font/ibm-plex-mono-v20-latin-600.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --------------------------------------------------------------------------
   Muka cadangan ber-metrik — memperbaiki pergeseran tata letak saat font web
   selesai dimuat.

   Font dimuat dengan `display=swap`, jadi teks tergambar lebih dulu memakai
   font sistem lalu ditukar. Bila metrik keduanya berbeda, seluruh blok teks
   berubah ukuran pada saat penukaran dan halaman bergeser. Beranda mengalami
   CLS 0,299 karena itu — tiga kali ambang Core Web Vitals — sementara halaman
   lain hanya 0,008 karena teksnya tidak sebesar hero.

   Nilai di bawah membuat font sistem menempati ruang yang SAMA dengan font web
   sebelum penukaran terjadi, sehingga tidak ada yang bergeser. Angkanya diukur
   di peramban, bukan disalin dari tabel: lebar untai contoh dan
   fontBoundingBox tiap font dibandingkan lewat canvas TextMetrics.

     size-adjust     = lebar_font_web / lebar_font_sistem
     ascent-override = ascent_font_web / size-adjust
     descent-override= descent_font_web / size-adjust

   Arial dan Times New Roman dipakai sebagai sumber karena tersedia di hampir
   semua sistem. Bila keduanya tidak ada, muka ini gagal dimuat dan rantai
   cadangan berikutnya di --font-ui / --font-display yang dipakai; halaman
   tetap benar, hanya kehilangan koreksi metriknya.

   Bila keluarga font diganti, UKUR ULANG. Angka lama pada font baru justru
   memperbesar pergeseran. -------------------------------------------------- */

@font-face {
  font-family: 'Jakarta Fallback';
  src: local('Arial'), local('Helvetica Neue'), local('Liberation Sans');
  size-adjust: 102.7%;
  ascent-override: 101.27%;
  descent-override: 21.42%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Serif Fallback';
  src: local('Times New Roman'), local('Liberation Serif'), local('Georgia');
  size-adjust: 101.75%;
  ascent-override: 102.21%;
  descent-override: 33.42%;
  line-gap-override: 0%;
}

:root {
  /* ---- Brand: Biru (primer) ---- */
  --be-blue-950: #030f3f;
  --be-blue-900: #041a6e;
  --be-blue-800: #062196;
  --be-blue-700: #072cbd;
  --be-blue-600: #1246d6;
  --be-blue-500: #1b5be8;
  --be-blue-400: #2287f6;
  --be-blue-300: #30b3ff;
  --be-blue-200: #86d2ff;
  --be-blue-100: #cfeaff;
  --be-blue-050: #eaf5ff;

  /* ---- Brand: Surya (aksen) ---- */
  /* sun-700 hanya dipakai sebagai warna teks/ikon di atas latar --be-sun-050.
     #c25a00 hanya mencapai 4,16:1 di sana — gagal WCAG AA untuk badge 12px.
     Digelapkan ke #a34b00 (5,55:1) tanpa keluar dari nuansa surya. */
  --be-sun-700: #a34b00;
  --be-sun-600: #fb7806;
  --be-sun-500: #ff8f1f;
  --be-sun-400: #ffa51f;
  --be-sun-300: #ffd100;
  --be-sun-100: #ffeeb8;
  --be-sun-050: #fff8e1;

  /* ---- Netral (dingin, condong biru agar menyatu dengan brand) ---- */
  --ink-950: #060b16;
  --ink-900: #0b1220;
  --ink-800: #162032;
  --ink-700: #1e2a3d;
  --ink-600: #33415a;
  --ink-500: #4a5a72;
  --ink-400: #6b7a92;
  --ink-300: #97a3b6;
  --ink-200: #c3cbd9;
  --ink-100: #dde4f0;
  --ink-050: #eef2f9;

  --paper: #ffffff;
  --paper-soft: #f6f8fc;
  --paper-warm: #fdfaf3;

  /* ---- Token semantik ---- */
  --bg: var(--paper);
  --bg-alt: var(--paper-soft);
  --surface: var(--paper);
  --surface-raised: var(--paper);
  --text: var(--ink-900);
  --text-muted: var(--ink-500);
  /* Sengaja tidak memakai --ink-400 (#6b7a92): token ini selalu dipasangkan
     dengan --text-sm (13px) pada .hint dan catatan kaki, dan #6b7a92 hanya
     mencapai 4,35:1 di atas putih. #5d6c85 memberi 5,32:1. */
  --text-faint: #5d6c85;
  --text-invert: #ffffff;
  --line: var(--ink-100);
  --line-strong: var(--ink-200);
  --accent: var(--be-blue-700);
  --accent-hover: var(--be-blue-800);
  --accent-soft: var(--be-blue-050);
  --focus: var(--be-blue-400);

  /* ---- Kanal WhatsApp ----
     Bukan hijau resmi WhatsApp (#25D366), melainkan pilihan sendiri sejak awal.
     Digelapkan dari #1faa54: teks putih di atasnya hanya mencapai 3,03:1, gagal
     WCAG AA untuk label tombol berukuran biasa. #148544 memberi 4,70:1 tanpa
     keluar dari nuansa hijau yang membuat tombolnya langsung dikenali. */
  --wa: #148544;
  --wa-hover: #0f6b36;

  /* ---- Status semantik (dipakai untuk tabel teknis & badge) ---- */
  --ok: #0e7a4a;
  --ok-soft: #e4f6ec;
  --warn: #9a5b00;
  --warn-soft: var(--be-sun-050);
  --danger: #b02020;
  --danger-soft: #fdeaea;

  /* ---- Gradien tanda tangan ---- */
  --grad-brand: linear-gradient(112deg, var(--be-blue-700) 0%, var(--be-blue-300) 100%);
  --grad-sun: linear-gradient(112deg, var(--be-sun-600) 0%, var(--be-sun-300) 100%);

  /* Gradien latar untuk section bertulisan terang.
     Stop paling terang sengaja dibatasi di --be-blue-600 (#1246d6):
     memakai --be-blue-400 membuat kontras teks sekunder turun ke 1,7:1
     di sudut terang — jauh di bawah ambang WCAG AA 4,5:1. */
  --grad-dawn: linear-gradient(140deg, var(--be-blue-900) 0%, var(--be-blue-700) 55%, var(--be-blue-600) 100%);
  --grad-night: linear-gradient(160deg, var(--be-blue-950) 0%, var(--be-blue-900) 55%, #0a2a80 100%);

  /* ---- Tipografi ----
     Tiga peran, sengaja dipisah agar kontras type-pairing benar-benar terasa:

     display : Source Serif 4 — serif variabel dengan sumbu optical size
               (opsz 8–60). HANYA untuk h1 dan h2. Kontrasnya rendah dan
               wataknya dokumen teknis, bukan dekoratif, sehingga judul
               terbaca sebagai pernyataan yang dapat diperiksa.
               Menggantikan Fraunces, yang sudah terlalu lekat dengan
               tampilan default desain hasil AI dan karena itu justru
               melemahkan pembeda visual situs ini.
     ui      : Plus Jakarta Sans — typeface buatan Indonesia (resmi DKI Jakarta),
               pilihan sadar agar identitas terasa lokal. Dipakai untuk judul
               kecil (h3–h5), tombol, label, nama brand, dan angka statistik.
     mono    : IBM Plex Mono — angka teknis, satuan, dan spesifikasi.

     Inter dihapus: sebagai sans geometris humanis dengan proporsi yang mirip
     Plus Jakarta Sans, ia tidak memberi kontras apa pun. Menghapusnya juga
     memangkas 141 KB unduhan font. */
  /* Source Serif 4 (Adobe), sumbu optical size 8–60. Dipilih menggantikan
     Fraunces: kontrasnya lebih rendah dan wataknya dokumen-teknis, yang
     lebih selaras dengan posisi editorial "edukasi di atas promosi" dan
     naskah yang bersandar pada angka serta nomor standar.

     Cadangannya BUKAN Georgia langsung, melainkan muka ber-metrik di bawah.
     Alasannya ada di komentar @font-face itu. */
  --font-display: 'Source Serif 4', 'Serif Fallback', Georgia, 'Times New Roman', serif;
  --font-ui: 'Plus Jakarta Sans', 'Jakarta Fallback', 'Segoe UI', system-ui, sans-serif;
  --font-body: var(--font-ui);
  --font-mono: 'IBM Plex Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;

  --text-xs: 0.75rem;
  --text-sm: 0.8125rem;
  /* Satu anak tangga antara --text-sm dan --text-base. Dipakai paragraf
     pendukung yang masih harus terbaca sebagai isi, bukan sebagai catatan
     kaki. Di layar sempit nilainya bertemu --text-base, dan itu disengaja. */
  --text-note: 0.9375rem;
  --text-base: clamp(0.9375rem, 0.9rem + 0.18vw, 1.0625rem);
  --text-lead: clamp(1.0625rem, 0.98rem + 0.42vw, 1.3125rem);
  --text-h4: clamp(1.0625rem, 1rem + 0.34vw, 1.25rem);
  --text-h3: clamp(1.25rem, 1.1rem + 0.7vw, 1.75rem);
  --text-h2: clamp(1.75rem, 1.4rem + 1.6vw, 3rem);
  --text-h1: clamp(2.25rem, 1.6rem + 2.9vw, 4.25rem);
  /* Hanya dipakai .hero h1. Riwayat kalibrasi:
       6rem   (96px) — dikalibrasi untuk Plus Jakarta Sans
       3,5rem (56px) — diturunkan karena Fraunces jauh lebih lebar; baris
                       "Matahari bekerja siang." butuh 874px pada 92px,
                       sedangkan kolom teks hero hanya 555px, sehingga judul
                       pecah jadi 5 baris dan hero membengkak ke 1213px.

     Nilai 3,5rem DIPERTAHANKAN saat pindah ke Source Serif 4. Diukur di
     peramban (16 Agustus 2026, font variabel dan sumbu optical size persis
     seperti yang dipakai situs): ukuran terbesar yang membuat baris
     "Matahari bekerja siang." tetap muat kolom 555px adalah 56px — sama
     persis dengan nilai ini.

     Artinya 3,5rem bukan angka aman berjarak, melainkan tepat di batas.
     Menaikkannya sedikit saja memecah baris terpanjang dan mengembalikan
     hero yang membengkak. Jangan diubah tanpa mengukur ulang, dan bila
     naskah hero diganti dengan baris yang lebih panjang, ukur lagi. */
  --text-mega: clamp(2.25rem, 1.1rem + 3vw, 3.5rem);

  --leading-tight: 1.08;
  --leading-snug: 1.25;
  --leading-normal: 1.65;

  --track-tight: -0.03em;
  --track-snug: -0.015em;
  --track-wide: 0.08em;

  /* ---- Ritme spasi (tidak seragam — sengaja bertingkat) ---- */
  --space-3xs: 0.25rem;
  --space-2xs: 0.5rem;
  --space-xs: 0.75rem;
  --space-sm: 1rem;
  --space-md: 1.5rem;
  --space-lg: 2.25rem;
  --space-xl: 3.5rem;
  --space-2xl: clamp(3.5rem, 2.5rem + 4vw, 6rem);
  --space-section: clamp(4rem, 2.8rem + 5.4vw, 8.5rem);

  /* ---- Bentuk (radius bertingkat, bukan seragam) ---- */
  --radius-xs: 4px;
  --radius-sm: 8px;
  --radius-md: 14px;
  --radius-lg: 22px;
  --radius-xl: 32px;
  --radius-pill: 999px;

  /* ---- Elevasi ---- */
  --shadow-xs: 0 1px 2px rgba(11, 18, 32, 0.06);
  --shadow-sm: 0 2px 8px rgba(11, 18, 32, 0.06), 0 1px 2px rgba(11, 18, 32, 0.04);
  --shadow-md: 0 12px 28px -12px rgba(7, 44, 189, 0.22), 0 2px 6px rgba(11, 18, 32, 0.05);
  --shadow-lg: 0 32px 64px -28px rgba(7, 44, 189, 0.32), 0 4px 12px rgba(11, 18, 32, 0.06);
  --shadow-sun: 0 18px 40px -18px rgba(251, 120, 6, 0.5);

  /* ---- Gerak ---- */
  --dur-fast: 140ms;
  --dur: 260ms;
  --dur-slow: 520ms;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  /* ---- Layout ---- */
  --container: 1200px;
  --container-wide: 1360px;
  /* Dua lebar antara --container-prose dan --container penuh. Halaman yang
     isinya satu kolom panjang (akordeon, linimasa, daftar istilah) terbaca
     buruk pada 1200px, tetapi 68ch terlalu sempit untuk menampung tabel. */
  --container-narrow: 56rem;
  --container-mid: 64rem;
  --container-prose: 68ch;
  --gutter: clamp(1.125rem, 0.6rem + 2.4vw, 2.5rem);
  --header-h: 72px;
  --z-header: 100;
  --z-drawer: 200;
  --z-toast: 300;
}

/* Blok bertema gelap — dipakai untuk section "malam hari / backup baterai" */
.theme-dark {
  --bg: var(--be-blue-950);
  --bg-alt: var(--be-blue-900);
  --surface: rgba(255, 255, 255, 0.045);
  --surface-raised: rgba(255, 255, 255, 0.08);
  --text: #f2f6ff;
  --text-muted: #a9bbdd;
  --text-faint: #8296bd;
  --line: rgba(255, 255, 255, 0.12);
  --line-strong: rgba(255, 255, 255, 0.2);
  --accent: var(--be-sun-300);
  --accent-hover: var(--be-sun-400);
  --accent-soft: rgba(255, 209, 0, 0.12);
  --focus: var(--be-sun-300);
  color-scheme: dark;

  /* WAJIB. Mendefinisikan ulang --text saja tidak cukup: satu-satunya aturan
     yang membaca var(--text) adalah `body`, dan warna diwariskan sebagai nilai
     terhitung. Tanpa baris ini seluruh teks di dalam blok tetap memakai tinta
     gelap milik body — praktis tidak terlihat di atas latar biru tua. */
  color: var(--text);
}

/* ===== assets/css/base.css ===== */
/* ==========================================================================
   Barokah Energy — Reset & elemen dasar
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1.5rem);

  /* `clip`, bukan `hidden`, dan di `html` — bukan di `body`.

     Laci navigasi seluler diparkir `translateX(100%)` selebar layar, sehingga
     scrollWidth dokumen menjadi dua kali lebar viewport di seluruh halaman.
     `overflow-x: hidden` menyembunyikannya tetapi TETAP membuat area gulir,
     dan akibatnya terlihat pengunjung: membuka laci melompatkan halaman ~36px
     ke kanan sehingga teks terpotong di tepi kiri, dan di peramban seluler
     layout viewport ikut melebar — elemen `position: fixed` berpatokan padanya,
     jadi tombol WhatsApp yang dipatok `right` terdorong ke luar layar dan baru
     terlihat setelah tampilan diperkecil.

     Diletakkan di `html` karena aturan yang sama di `body` tidak cukup: nilai
     itu dirambatkan ke viewport sebagai area gulir, dan `body` sendiri berhenti
     memotong. Diukur di peramban — dengan aturan ini scrollWidth dokumen turun
     dari 780px menjadi 390px pada viewport 390px, dan halaman tidak lagi
     bergeser saat laci dibuka. */
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  font-feature-settings: 'cv02', 'cv03', 'cv11';
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;

  /* Pasangan dari aturan di `html`. Yang di `html` menghapus area gulirnya;
     yang ini membuat `body` benar-benar memotong isinya, sehingga scrollWidth
     dokumen ikut turun ke lebar viewport. Peramban seluler membaca angka itu
     saat menentukan lebar layout viewport, jadi selisihnya bukan kosmetik. */
  overflow-x: clip;
}

/* Mengunci gulir badan saat laci navigasi terbuka. Sumbu mendatar dinyatakan
   `clip` secara eksplisit: memasang `overflow-y: hidden` sendirian akan memaksa
   sumbu mendatar dari `visible` menjadi `auto`, dan itu mengembalikan area gulir
   yang baru saja dihapus di `html` — tepat pada saat laci membutuhkannya hilang. */
body.is-locked {
  overflow-y: hidden;
  overflow-x: clip;
}

h1,
h2,
h3,
h4,
h5 {
  margin: 0;
  font-family: var(--font-ui);
  font-weight: 800;
  line-height: var(--leading-tight);
  letter-spacing: var(--track-tight);
  text-wrap: balance;
}

/* Hanya h1 dan h2 yang memakai serif display. h3–h5 tetap sans karena
   dipakai di kartu, tabel spesifikasi, dan akordeon FAQ — tempat yang
   butuh kepadatan dan kemudahan dipindai, bukan karakter.

   Bobot 700 dipertahankan dari era Fraunces, tetapi alasannya berubah.
   Fraunces pekat pada bobot yang sama sehingga 700 sudah cukup. Source
   Serif 4 kontrasnya lebih rendah dan goresnya lebih tenang, jadi 700
   justru dibutuhkan agar judul tetap punya bobot di samping Plus Jakarta
   Sans yang tebal.

   TODO(verify): tracking -0,015em (--track-snug) dulu dilonggarkan dari
   -0,03em karena serif berkontras tinggi butuh ruang antar huruf lebih
   lega. Source Serif 4 kontrasnya lebih rendah dan mungkin sanggup
   dirapatkan kembali. Periksa di peramban sebelum mengubah. */
h1,
h2 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: var(--track-snug);
}

h1 { font-size: var(--text-h1); }
h2 { font-size: var(--text-h2); }
h3 { font-size: var(--text-h3); line-height: var(--leading-snug); }
h4 { font-size: var(--text-h4); line-height: var(--leading-snug); letter-spacing: var(--track-snug); }

p {
  margin: 0;
  text-wrap: pretty;
}

a {
  color: var(--accent);
  text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
  text-underline-offset: 0.22em;
  transition: color var(--dur-fast) var(--ease-out),
              text-decoration-color var(--dur-fast) var(--ease-out);
}

a:hover {
  color: var(--accent-hover);
  text-decoration-color: currentColor;
}

img,
svg,
video {
  display: block;
  max-width: 100%;
  height: auto;
}

ul,
ol {
  margin: 0;
  padding-left: 1.15em;
}

li + li {
  margin-top: 0.4em;
}

strong,
b {
  font-weight: 700;
  color: color-mix(in srgb, var(--text) 92%, var(--accent));
}

hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: var(--space-lg) 0;
}

code,
kbd,
samp {
  font-family: var(--font-mono);
  font-size: 0.9em;
}

/* Angka teknis selalu sejajar — penting untuk tabel spesifikasi */
.num,
table td,
table th {
  font-variant-numeric: tabular-nums;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
}

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
  border-radius: var(--radius-xs);
}

::selection {
  background: var(--be-sun-300);
  color: var(--ink-900);
}

/* --- Iframe cadangan Google Tag Manager ---
   Snippet resmi GTM menyembunyikan iframe ini lewat atribut style=. Di situs
   ini atribut itu diblokir style-src 'self' dan digagalkan tools/check.js,
   jadi penyembunyiannya dipindahkan ke sini. Iframe ber-display:none tetap
   memuat src-nya, sehingga fungsinya tidak berubah. */
.gtm-noscript {
  display: none;
  visibility: hidden;
}

/* --- Utilitas aksesibilitas --- */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: 0;
  left: var(--space-sm);
  transform: translateY(-140%);
  z-index: calc(var(--z-header) + 10);
  padding: 0.75rem 1.25rem;
  background: var(--be-blue-700);
  color: #fff;
  font-weight: 600;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  text-decoration: none;
  transition: transform var(--dur) var(--ease-out);
}

.skip-link:focus {
  transform: translateY(0);
  color: #fff;
}

/* --- Hormati preferensi pengurangan gerak --- */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  .site-header,
  .site-footer,
  .floating-cta,
  .cookie-bar {
    display: none !important;
  }

  body {
    color: #000;
    background: #fff;
  }
}

/* ===== assets/css/layout.css ===== */
/* ==========================================================================
   Barokah Energy — Layout: container, header, navigasi, footer
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--wide { max-width: var(--container-wide); }
.container--mid { max-width: var(--container-mid); }
.container--narrow { max-width: var(--container-narrow); }
.container--prose { max-width: var(--container-prose); }

.section {
  padding-block: var(--space-section);
  position: relative;
}

.section--tight { padding-block: var(--space-2xl); }
.section--alt { background: var(--bg-alt); }

/* Kertas hangat — pemecah ritme. Selang-seling putih/abu-biru yang rapi
   justru membuat halaman terasa mekanis. Pakai maksimal SATU kali per
   halaman, di section yang memang ingin ditonjolkan. */
.section--warm { background: var(--paper-warm); }

/* Garis diagonal — adaptasi elemen "the edge" jadi berkas sinar matahari */
.section--rayed {
  overflow: hidden;
  isolation: isolate;
}

.section--rayed::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(112deg, transparent 38%, rgba(48, 179, 255, 0.07) 38.4%, rgba(48, 179, 255, 0.07) 46%, transparent 46.4%),
    linear-gradient(112deg, transparent 62%, rgba(255, 209, 0, 0.1) 62.3%, rgba(255, 209, 0, 0.1) 66%, transparent 66.3%);
  pointer-events: none;
}

/* --- Kepala section --- */
.section-head {
  max-width: 62ch;
  margin-bottom: var(--space-xl);
}

.section-head--center {
  margin-inline: auto;
  text-align: center;
}

.section-head p {
  margin-top: var(--space-sm);
  font-size: var(--text-lead);
  color: var(--text-muted);
}

/* Kepala section asimetris: judul di kiri, lede di kanan, rata bawah.
   Alternatif untuk tumpukan vertikal eyebrow → judul → deskripsi yang
   kalau dipakai di setiap section membuat halaman terasa dicetak mesin.

   Blok ini WAJIB berada setelah `.section-head p` di atas: keduanya
   berspesifisitas sama (0,1,1), jadi yang menang adalah yang terakhir. */
.section-head--split {
  max-width: none;
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: var(--space-sm) var(--space-2xl);
  align-items: end;
}

.section-head--split p { margin-top: 0; }

@media (max-width: 860px) {
  .section-head--split {
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
  }

  .section-head--split p { margin-top: var(--space-sm); }
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  margin-bottom: var(--space-sm);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text-muted);
}

.eyebrow::before {
  content: '';
  width: 1.75rem;
  height: 2px;
  border-radius: 2px;
  background: var(--grad-sun);
}

.section-head--center .eyebrow { justify-content: center; }

/* --- Grid utilitas --- */
.grid { display: grid; gap: var(--space-md); }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* Grid yang sengaja lebih sempit dari kolom induknya, dipusatkan. */
.grid--narrow { max-width: 60rem; margin-inline: auto; }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid-gap-lg { gap: var(--space-lg); }

@media (max-width: 960px) {
  .grid-3,
  .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 620px) {
  .grid-2,
  .grid-3,
  .grid-4 { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   Header
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: saturate(180%) blur(16px);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur) var(--ease-out),
              box-shadow var(--dur) var(--ease-out),
              background-color var(--dur) var(--ease-out);
}

.site-header.is-stuck {
  border-bottom-color: var(--line);
  box-shadow: 0 6px 24px -18px rgba(11, 18, 32, 0.4);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  min-height: var(--header-h);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  flex-shrink: 0;
}

.brand img { height: 34px; width: auto; }
.brand__mark { height: 34px; width: 34px; }

.brand__text {
  display: flex;
  flex-direction: column;
  line-height: 1.05;
}

.brand__name {
  font-family: var(--font-ui);
  font-weight: 800;
  font-size: 1.0625rem;
  letter-spacing: var(--track-snug);
  color: var(--ink-900);
}

.brand__tag {
  font-family: var(--font-mono);
  font-size: 0.5625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* Lebih gelap dari --text-faint: header semi-transparan (82% putih), jadi
     saat hero gelap melintas di bawahnya latar efektif turun ke ~#d2d4dc.
     --ink-500 tetap 4,74:1 di kondisi terburuk itu. */
  color: var(--ink-500);
}

/* --- Navigasi utama --- */
.nav {
  display: flex;
  align-items: center;
  gap: 0.15rem;
  margin-left: auto;
}

.nav__item { position: relative; }

.nav__link {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 0.55rem 0.8rem;
  border-radius: var(--radius-sm);
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ink-700);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}

.nav__link:hover,
.nav__item:focus-within > .nav__link {
  background: var(--accent-soft);
  color: var(--be-blue-800);
}

.nav__link[aria-current='page'] {
  color: var(--be-blue-700);
  font-weight: 700;
}

.nav__link[aria-current='page']::after {
  content: '';
  position: absolute;
  left: 0.8rem;
  right: 0.8rem;
  bottom: 0.15rem;
  height: 2px;
  border-radius: 2px;
  background: var(--grad-sun);
}

.nav__caret {
  width: 0.65em;
  height: 0.65em;
  transition: transform var(--dur-fast) var(--ease-out);
}

.nav__item:hover .nav__caret,
.nav__item:focus-within .nav__caret { transform: rotate(180deg); }

/* --- Megamenu --- */
.megamenu {
  position: absolute;
  top: calc(100% + 0.5rem);
  left: 50%;
  translate: -50% 0;
  width: max-content;
  max-width: min(46rem, 90vw);
  padding: var(--space-md);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out),
              visibility var(--dur);
}

.nav__item:hover > .megamenu,
.nav__item:focus-within > .megamenu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.megamenu__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(13rem, 1fr));
  gap: 0.35rem;
}

.megamenu__link {
  display: block;
  padding: 0.7rem 0.85rem;
  border-radius: var(--radius-sm);
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-out);
}

.megamenu__link:hover { background: var(--accent-soft); }

.megamenu__title {
  display: block;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 0.9375rem;
  color: var(--ink-900);
}

.megamenu__desc {
  display: block;
  margin-top: 0.15rem;
  font-size: var(--text-sm);
  line-height: 1.45;
  color: var(--text-muted);
}

.megamenu__foot {
  margin-top: var(--space-sm);
  padding-top: var(--space-sm);
  border-top: 1px solid var(--line);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-shrink: 0;
}

/* --- Tombol hamburger --- */
.nav-toggle {
  display: none;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}

.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  display: block;
  width: 18px;
  height: 2px;
  border-radius: 2px;
  background: var(--ink-900);
  transition: transform var(--dur) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}

.nav-toggle__bars::before,
.nav-toggle__bars::after {
  content: '';
  position: absolute;
}

.nav-toggle__bars::before { transform: translateY(-6px); }
.nav-toggle__bars::after { transform: translateY(6px); }

.nav-toggle[aria-expanded='true'] .nav-toggle__bars { background: transparent; }
.nav-toggle[aria-expanded='true'] .nav-toggle__bars::before { transform: rotate(45deg); }
.nav-toggle[aria-expanded='true'] .nav-toggle__bars::after { transform: rotate(-45deg); }

/* 1160px, bukan angka bulat sembarang: bar nav horizontal membutuhkan 1135 px
   (brand 193 + menu 585 + tombol aksi 309 + dua gap 24). Di bawah itu menu
   bertabrakan dengan logo. Ambangnya harus sama persis dengan `mobileQuery`
   di assets/js/main.js — kalau berbeda, drawer bisa terbuka tanpa tombolnya
   terlihat, atau sebaliknya. */
@media (max-width: 1160px) {
  .nav-toggle { display: inline-flex; }

  /* Tinggi laci dinyatakan eksplisit, BUKAN lewat `bottom: 0`.

     `.site-header` memakai `backdrop-filter`, dan properti itu menjadikan
     header sebagai containing block bagi anaknya yang `position: fixed` —
     termasuk laci ini. Dengan `inset: var(--header-h) 0 0 0`, `bottom: 0`
     karena itu diukur terhadap kotak header setinggi 72px, bukan terhadap
     viewport: laci menyusut menjadi 80px sementara isinya butuh 427px, dan
     yang terlihat pengunjung hanya "Beranda" beserta potongan "Sistem".
     Lima menu sisanya ada di dalam kotak gulir setinggi 80px yang tidak
     tampak sebagai kotak gulir.

     `height` yang dihitung dari unit viewport melewati jebakan itu: nilainya
     sama baik header menjadi containing block maupun tidak, jadi tidak
     bergantung pada apakah peramban menerapkan aturan backdrop-filter tersebut.
     `100dvh` menyusul sebagai penimpa agar bilah alamat peramban seluler yang
     menyusut tidak memotong butir menu terakhir; peramban yang belum
     mengenalnya berhenti di baris `100vh` di atasnya. */
  .nav {
    position: fixed;
    top: var(--header-h);
    right: 0;
    left: 0;
    height: calc(100vh - var(--header-h));
    height: calc(100dvh - var(--header-h));
    z-index: var(--z-drawer);
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    margin: 0;
    padding: var(--space-md) var(--gutter) var(--space-2xl);
    background: var(--paper);
    overflow-y: auto;
    overscroll-behavior: contain;
    transform: translateX(100%);
    visibility: hidden;

    /* `visibility` ditunda, bukan ditransisikan.

       Nilai ini yang menahan tautan laci keluar dari urutan Tab selama tertutup,
       jadi ia tidak boleh sekadar dihapus. Tetapi mentransisikannya membuat
       Chrome menahan nilainya di `hidden` sepanjang 520ms animasi — diukur, dua
       frame setelah laci dibuka nilainya masih `hidden` — dan `focus()` ke dalam
       subpohon tersembunyi gagal tanpa suara. Pemindahan fokus ke butir menu
       pertama karena itu tidak pernah berhasil.

       Bentuk di bawah menjadikannya saklar berjeda: saat dibuka ia menyala
       seketika (0s tanpa jeda, lihat .nav.is-open), saat ditutup ia baru padam
       setelah lacinya selesai bergeser keluar, sehingga animasi keluarnya tetap
       terlihat. */
    transition: transform var(--dur-slow) var(--ease-out),
                visibility 0s linear var(--dur-slow);
  }

  .nav.is-open {
    transform: translateX(0);
    visibility: visible;
    /* `visibility` sengaja TIDAK ada di daftar ini, bukan disetel 0s. Reset
       prefers-reduced-motion di base.css memaksa `transition-duration` ke
       0,00001s dengan !important, jadi durasi 0 pun tetap menjadi transisi
       nyata — dan pada tick pertama nilainya masih `hidden`, sehingga
       pemindahan fokus gagal lagi persis di lingkungan yang paling
       membutuhkannya. Properti yang tidak didaftarkan berubah seketika dan
       tidak dapat ditawar oleh penimpa mana pun. */
    transition: transform var(--dur-slow) var(--ease-out);
  }

  /* `flex`, bukan `inline-flex` yang diwarisi dari lebar penuh. Baris menu di
     laci menjadi selebar laci, dan dua hal ikut benar dengan sendirinya:
     garis pemisah di bawahnya berhenti bergerigi mengikuti panjang teks, dan
     `justify-content: space-between` akhirnya punya ruang untuk dibagi
     sehingga tanda panah submenu duduk di tepi kanan, bukan menempel pada
     labelnya. Bidang sentuhnya pun menjadi selebar baris. */
  .nav__link {
    display: flex;
    padding: 0.9rem 0.25rem;
    font-size: 1.0625rem;
    font-weight: 600;
    border-bottom: 1px solid var(--line);
    border-radius: 0;
    justify-content: space-between;
  }

  .nav__link[aria-current='page']::after { display: none; }

  .megamenu {
    position: static;
    translate: none;
    width: auto;
    max-width: none;
    padding: 0 0 var(--space-sm);
    border: 0;
    box-shadow: none;
    opacity: 1;
    visibility: visible;
    transform: none;
    display: none;
  }

  .nav__item.is-open .megamenu { display: block; }
  .nav__item.is-open .nav__caret { transform: rotate(180deg); }

  .megamenu__grid { grid-template-columns: minmax(0, 1fr); }
  .megamenu__link { padding: 0.6rem 0.75rem; }
  .header-actions .btn--ghost { display: none; }

  /* Di lebar penuh, `.nav { margin-left: auto }` yang mendorong menu dan tombol
     aksi ke tepi kanan. Di bawah ambang ini nav menjadi `position: fixed` dan
     keluar dari aliran, sehingga dorongan itu hilang bersamanya dan tombol aksi
     menempel pada merek — menyisakan ~100px kosong di kanan dengan hamburger
     terparkir di tengah baris. */
  .header-actions { margin-left: auto; }
}

/* Baris header menyusut bertingkat, bukan sekaligus.

   Sampai perbaikan ini isinya dijumlahkan 438px pada viewport 360px — merek
   193 + jarak 24 + tombol aksi 190 + talang 31 — dan yang terdorong keluar
   adalah anak terakhir: tombol hamburger. Ia mulai di x=381, jadi di seluruh
   16 halaman menu itu tidak dapat disentuh sama sekali di bawah ~430px.
   `overflow-x` memotongnya tanpa scrollbar, sehingga tidak ada tanda apa pun
   bahwa tombolnya ada.

   Yang dilepas dilepas menurut nilainya, dari yang paling sedikit membawa
   informasi: tagline, lalu kata "Gratis", lalu nama merek — logo dan tombol
   hamburger tidak pernah ikut, dan lambang merek tetap menjadi tautan ke
   beranda. Ambangnya diukur di peramban, bukan dibulatkan ke angka perangkat. */
@media (max-width: 600px) {
  .header-inner { gap: var(--space-xs); }
  .header-actions { gap: 0.5rem; }
  .btn__tail { display: none; }

  /* Dilingkupi `.site-header`. Blok merek yang sama dipakai footer, dan di sana
     ia berdiri sendiri di kolom vertikal yang lapang — bukan berebut satu baris
     dengan tombol. Tanpa lingkup ini footer ikut kehilangan tagline, lalu nama
     mereknya, justru di layar tempat blok itu punya ruang paling banyak. */
  .site-header .brand__tag { display: none; }
  .site-header .brand__name { font-size: 1rem; }
}

@media (max-width: 420px) {
  .site-header .brand__text { display: none; }
}

/* ==========================================================================
   Footer
   ========================================================================== */

.site-footer {
  background: var(--grad-night);
  color: #e8eeff;
  padding-block: var(--space-2xl) var(--space-lg);
  position: relative;
  overflow: hidden;
}

.site-footer::before {
  content: '';
  position: absolute;
  top: -30%;
  right: -8%;
  width: 40rem;
  height: 40rem;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 209, 0, 0.14) 0%, transparent 65%);
  pointer-events: none;
}

.footer-grid {
  position: relative;
  display: grid;
  grid-template-columns: minmax(16rem, 1.4fr) repeat(3, minmax(9rem, 1fr));
  gap: var(--space-lg) var(--space-md);
}

@media (max-width: 900px) {
  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 540px) {
  .footer-grid { grid-template-columns: minmax(0, 1fr); }
}

.footer-brand__blurb {
  margin-top: var(--space-sm);
  max-width: 34ch;
  color: #b8c8ee;
  font-size: 0.9375rem;
}

.footer-col h3 {
  font-size: 0.8125rem;
  font-family: var(--font-mono);
  font-weight: 500;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--be-sun-300);
  margin-bottom: var(--space-sm);
}

.footer-col ul {
  list-style: none;
  padding: 0;
}

.footer-col li + li { margin-top: 0.55rem; }

.footer-col a {
  color: #cdd9f5;
  font-size: 0.9375rem;
  text-decoration: none;
}

.footer-col a:hover {
  color: #fff;
  text-decoration: underline;
  text-underline-offset: 0.24em;
}

.footer-contact {
  list-style: none;
  padding: 0;
  margin-top: var(--space-md);
  font-size: 0.9375rem;
  color: #cdd9f5;
}

.footer-contact li {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
}

/* Nama brand di footer berdiri di atas latar gelap, kebalikan dari header. */
.site-footer .brand__name { color: #fff; }
.site-footer .brand__tag { color: #8fa6d8; }

.footer-contact li + li { margin-top: 0.6rem; }

/* Nama badan hukum memimpin blok alamat: ia yang menerangkan alamat di
   bawahnya, bukan baris pertama alamat itu sendiri. Putih penuh terhadap navy
   footer (di atas 12:1) memberinya satu tingkat di atas baris alamat yang
   mewarisi #cdd9f5, sehingga urutan bacanya jelas tanpa menambah ukuran. */
.footer-contact__legal {
  display: block;
  margin-bottom: 0.2rem;
  font-weight: 700;
  color: #fff;
}

/* Wilayah layanan mengekor di bawah alamat kantor: informasi pendukung,
   bukan baris alamat kelima. */
.footer-contact__area {
  display: block;
  margin-top: 0.35rem;
  /* #9db0d8 hanya mencapai 4,57:1 di titik paling terang footer (stop #0a2a80
     yang masih ditimpa radial surya 14 %). #a8bade memberi 5,15:1. */
  color: #a8bade;
  font-size: 0.875rem;
}

/* Telepon dan surel tidak punya aturan warna sendiri, sehingga jatuh ke warna
   tautan global var(--accent) = #072cbd. Biru tua brand di atas footer navy
   hanya mencapai 1,3:1: nomor telepon dan alamat surel praktis tidak terbaca
   di seluruh 15 halaman. Mewarisi #cdd9f5 dari .footer-contact memberi 8,7:1. */
.footer-contact a {
  color: inherit;
  text-decoration: none;
}

.footer-contact a:hover,
.footer-contact a:focus-visible {
  color: #fff;
  text-decoration: underline;
  text-underline-offset: 0.24em;
}

.footer-contact svg {
  width: 1.05em;
  height: 1.05em;
  margin-top: 0.35em;
  flex-shrink: 0;
  color: var(--be-blue-300);
}

/* Bidang sentuh tautan footer.

   Telepon, surel, dan seluruh tautan kolom navigasi tingginya hanya ~20px —
   yang terkecil di halaman, dan berada di area yang justru paling sering
   dituju dengan ibu jari.

   `min-height` tidak berlaku pada elemen inline, jadi tautannya perlu menjadi
   inline-flex lebih dulu. Jarak antar-baris dikembalikan ke nol sebagai
   gantinya: tinggi 44px sudah menyediakan ruang yang tadinya dibuat margin,
   sehingga footer tidak ikut memanjang.

   :has(a) dipakai agar hanya baris telepon dan surel yang ikut dipusatkan.
   Baris alamat empat baris tetap rata atas bersama ikonnya. Peramban tanpa
   dukungan :has melewatkan aturan ini dan kembali ke perilaku lama — sasaran
   yang lebih kecil, bukan tata letak yang rusak. */
@media (pointer: coarse) {
  .footer-col li + li { margin-top: 0; }

  .footer-col a,
  .footer-contact a,
  .footer-legal a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  .footer-contact li:has(a) {
    align-items: center;
    margin-top: 0;
  }

  .footer-contact li:has(a) svg { margin-top: 0; }
}

.footer-bottom {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm) var(--space-md);
  align-items: center;
  justify-content: space-between;
  margin-top: var(--space-2xl);
  padding-top: var(--space-md);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  font-size: var(--text-sm);
  color: #9aabd4;
}

.footer-legal {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  list-style: none;
  padding: 0;
}

.footer-legal li { margin: 0; }
.footer-legal a { color: #9aabd4; text-decoration: none; }
.footer-legal a:hover { color: #fff; }

/* ===== assets/css/components.css ===== */
/* ==========================================================================
   Barokah Energy — Komponen UI
   ========================================================================== */

/* --------------------------------------------------------------------------
   Tombol
   -------------------------------------------------------------------------- */
.btn {
  --btn-bg: var(--be-blue-700);
  --btn-fg: #fff;
  --btn-border: transparent;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55em;
  padding: 0.72rem 1.35rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-border);
  border-radius: var(--radius-pill);
  font-family: var(--font-ui);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: var(--track-snug);
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

.btn svg {
  width: 1.05em;
  height: 1.05em;
  flex-shrink: 0;
  transition: transform var(--dur) var(--ease-out);
}

.btn:hover {
  color: var(--btn-fg);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.btn:hover svg:last-child { transform: translateX(3px); }
.btn:active { transform: translateY(0); }

.btn--primary { --btn-bg: var(--be-blue-700); }
.btn--primary:hover { --btn-bg: var(--be-blue-800); }

.btn--sun {
  --btn-bg: transparent;
  --btn-fg: var(--ink-900);
  background: var(--grad-sun);
}
.btn--sun:hover { box-shadow: var(--shadow-sun); }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--ink-900);
  --btn-border: var(--line-strong);
}

.btn--ghost:hover {
  --btn-bg: var(--accent-soft);
  --btn-fg: var(--be-blue-800);
  --btn-border: var(--be-blue-200);
}

.btn--onDark {
  --btn-bg: rgba(255, 255, 255, 0.1);
  --btn-fg: #fff;
  --btn-border: rgba(255, 255, 255, 0.28);
  backdrop-filter: blur(6px);
}

.btn--onDark:hover { --btn-bg: rgba(255, 255, 255, 0.2); }

.btn--lg { padding: 0.95rem 1.75rem; font-size: 1rem; }
.btn--sm { padding: 0.5rem 1rem; font-size: var(--text-sm); }
.btn--block { width: 100%; }

/* Bidang sentuh pada perangkat sentuh.

   Ditanyakan lewat `pointer: coarse`, bukan lewat lebar layar: yang menentukan
   seberapa besar sebuah sasaran harus digambar adalah jenis penunjuknya, bukan
   berapa piksel layarnya. Tablet lebar dengan jari tetap butuh 44px; jendela
   peramban sempit dengan tetikus tidak.

   Tombol kecil tingginya 34px — cukup untuk WCAG 2.2 SC 2.5.8 (24px), di bawah
   44px yang menjadi acuan praktis kedua platform seluler. Yang paling terasa
   adalah tombol persetujuan cookie dan CTA di header: keduanya `.btn--sm` dan
   keduanya disentuh lebih dulu daripada apa pun di halaman.

   `.btn` biasa ikut disebut karena tingginya hanya ~37,6px: paddingnya sendiri
   tidak pernah mencapai 44px. `.btn--lg` melewatinya lewat padding, tetapi
   menyebutkan min-height di sini membuatnya tidak bergantung pada kebetulan
   itu. Karena `min-height` hanya menaikkan dan tidak pernah menurunkan, tidak
   ada satu pun tombol yang berubah tampilannya di layar bertetikus. */
@media (pointer: coarse) {
  .btn { min-height: 44px; }
}

.btn--wa {
  --btn-bg: var(--wa);
  --btn-fg: #fff;
}
.btn--wa:hover { --btn-bg: var(--wa-hover); }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  align-items: center;
}

/* Tautan panah — dipakai di dalam kartu */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 0.9375rem;
  text-decoration: none;
}

.link-arrow svg {
  width: 1em;
  height: 1em;
  transition: transform var(--dur) var(--ease-out);
}

.link-arrow:hover svg { transform: translateX(4px); }

/* Tinggi sentuh tautan panah.

   Teks 15px membuat bidang sentuhnya hanya ~20px. Sebagian besar `.link-arrow`
   memakai `.stretch` sehingga area kliknya sebesar kartu induknya dan sudah
   aman; yang berdiri sendiri di badan halaman tidak.

   Dinaikkan lewat min-height, bukan padding, supaya tidak ada jarak baru yang
   muncul di antara tautan dan paragraf di sebelahnya. Elemennya sudah
   inline-flex dengan align-items: center, jadi teksnya tetap di tengah. */
@media (pointer: coarse) {
  .link-arrow { min-height: 44px; }
}

/* --------------------------------------------------------------------------
   Badge / pil
   -------------------------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.3rem 0.7rem;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--be-blue-800);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

/* Badge terpanjang di situs ini adalah label keluaran tiap tahap di
   proses.html — "Output: inventaris beban & estimasi kapasitas" selebar 365px.
   Dengan `nowrap` ia menembus tepi kanan pada viewport 320 dan 360px dan
   terpotong tanpa sisa. `nowrap` tetap dipertahankan di layar lebar karena di
   sanalah gunanya: menjaga pil tetap satu baris di dalam baris meta yang padat.
   Yang dilepas hanya di lebar tempat pil itu memang tidak muat. */
@media (max-width: 560px) {
  .badge { white-space: normal; }
}

.badge--sun { background: var(--be-sun-050); color: var(--be-sun-700); }
.badge--ok { background: var(--ok-soft); color: var(--ok); }
.badge--warn { background: var(--warn-soft); color: var(--warn); }
.badge--danger { background: var(--danger-soft); color: var(--danger); }
.badge--outline { background: transparent; border: 1px solid var(--line-strong); color: var(--text-muted); }

.badge__dot {
  width: 0.45em;
  height: 0.45em;
  border-radius: 50%;
  background: currentColor;
}

/* --------------------------------------------------------------------------
   Kartu
   -------------------------------------------------------------------------- */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--space-md);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  transition: transform var(--dur) var(--ease-out),
              box-shadow var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out);
}

/* Tingkat heading ditentukan posisinya di dalam dokumen, skalanya
   ditentukan tempatnya di layar. Keduanya tidak selalu sejalan, jadi
   komponen ini menetapkan tampilannya sendiri agar naik-turunnya
   tingkat tidak mengubah apa pun yang terlihat. */
.card :is(h2, h3) {
  margin-bottom: 0.5rem;
  font-family: var(--font-ui);
  font-weight: 800;
  font-size: var(--text-h3);
  line-height: var(--leading-snug);
  letter-spacing: var(--track-tight);
}

/* Badge sebagai anak langsung .card. Tanpa align-self ia akan melar selebar
   kartu karena .card adalah flex column dengan align-items: stretch. */
.card > .badge {
  align-self: flex-start;
  margin-bottom: 0.7rem;
}

.card p {
  color: var(--text-muted);
  font-size: 0.9375rem;
}

.card__foot { margin-top: auto; padding-top: var(--space-md); }

.card--link:hover {
  transform: translateY(-4px);
  border-color: var(--be-blue-200);
  box-shadow: var(--shadow-md);
}

/* Seluruh kartu dapat diklik lewat overlay tautan */
.card--link .stretch::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.card__icon {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  margin-bottom: var(--space-sm);
  border-radius: var(--radius-md);
  background: var(--accent-soft);
  color: var(--be-blue-700);
}

.card__icon svg { width: 1.5rem; height: 1.5rem; }
.card__icon--sun { background: var(--be-sun-050); color: var(--be-sun-700); }

/* Di blok .theme-dark, kedua chip di atas memakai warna yang dirancang untuk
   kertas putih: latar terang dengan ikon gelap. Di atas biru tua hasilnya
   terbalik dan kontrasnya jatuh. Dibalik jadi chip transparan + ikon terang. */
.theme-dark .card__icon {
  background: rgba(48, 179, 255, 0.14);
  color: var(--be-blue-300);
}

.theme-dark .card__icon--sun {
  background: rgba(255, 209, 0, 0.14);
  color: var(--be-sun-300);
}

/* Kartu bernomor untuk urutan proses */
.card__step {
  font-family: var(--font-mono);
  font-size: 2.25rem;
  /* IBM Plex Mono hanya dimuat pada 400/500/600. Nilai 300 sebelumnya tidak
     pernah benar-benar berlaku — peramban jatuh ke 400. Disamakan agar niat
     kode sesuai hasil render; tidak ada perubahan visual. */
  font-weight: 400;
  line-height: 1;
  color: var(--be-blue-200);
  letter-spacing: var(--track-tight);
}

/* Kartu unggulan dalam bento — melebar dan bergradien */
/* Kartu berpasangan "yang benar / yang keliru": warnanya menandai isi,
   bukan sekadar hiasan. Dipakai berdampingan di faq.html. */
.card--ok { border-color: var(--ok); }
.card--danger { border-color: var(--danger); }

.card--feature {
  background: var(--grad-dawn);
  border-color: transparent;
  color: #fff;
  overflow: hidden;
}

.card--feature h3 { color: #fff; }
.card--feature p,
.card--feature .checklist li { color: #c7d8ff; }
.card--feature .link-arrow { color: var(--be-sun-300); }

.card--feature::after {
  content: '';
  position: absolute;
  right: -25%;
  bottom: -45%;
  width: 22rem;
  height: 22rem;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 209, 0, 0.28) 0%, transparent 62%);
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Statistik
   -------------------------------------------------------------------------- */
.stat {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.stat__value {
  font-family: var(--font-ui);
  font-size: clamp(1.85rem, 1.3rem + 2vw, 3rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: var(--track-tight);
  font-variant-numeric: tabular-nums;
  background: var(--grad-brand);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.stat__value--sun { background: var(--grad-sun); -webkit-background-clip: text; background-clip: text; }

.stat__label {
  font-size: var(--text-sm);
  color: var(--text-muted);
  line-height: 1.4;
}

.stat__unit {
  font-family: var(--font-mono);
  font-size: 0.5em;
  font-weight: 500;
  letter-spacing: 0;
}

/* --------------------------------------------------------------------------
   Tabel data teknis
   -------------------------------------------------------------------------- */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface);
  -webkit-overflow-scrolling: touch;
}

.table-wrap:focus-visible { outline-offset: 0; }

/* Tabel yang sudah berada di dalam kartu tidak perlu bingkai kedua. */
.table-wrap--flush { border: 0; }

table.data {
  width: 100%;
  min-width: 34rem;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

/* Tabel dua kolom pendek yang tidak perlu dipaksa menggulir di layar sempit. */
table.data--fluid { min-width: 0; }

/* --------------------------------------------------------------------------
   Varian gelap, dipakai tabel rincian di dalam panel hasil kalkulator.
   Sebelumnya dirakit dari 19 atribut style= yang mengulang warna garis yang
   sama di setiap sel.
   -------------------------------------------------------------------------- */
.table-wrap--dark {
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.14);
}

table.data--dark { color: #dbe6ff; }

table.data--dark th,
table.data--dark td { border-color: rgba(255, 255, 255, 0.1); }

table.data--dark td:first-child { color: #c8d7ff; }
table.data--dark .n { text-align: right; }

/* Sorotan baris versi terang memakai --accent-soft yang nyaris putih, dan di
   atas panel gelap itu menyilaukan. */
table.data--dark tbody tr:hover { background: rgba(255, 255, 255, 0.06); }

table.data caption {
  padding: var(--space-sm) var(--space-md);
  text-align: left;
  font-size: var(--text-sm);
  color: var(--text-muted);
  border-bottom: 1px solid var(--line);
}

table.data th,
table.data td {
  padding: 0.75rem 1rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--line);
}

table.data thead th {
  position: sticky;
  top: 0;
  background: var(--paper-soft);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-600);
  white-space: nowrap;
}

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

table.data td:first-child { font-weight: 600; color: var(--ink-900); }
table.data .n { font-family: var(--font-mono); white-space: nowrap; }

/* --------------------------------------------------------------------------
   Blok formula
   -------------------------------------------------------------------------- */
.formula {
  margin: var(--space-md) 0;
  padding: var(--space-md);
  background: var(--be-blue-950);
  border-radius: var(--radius-md);
  border-left: 4px solid var(--be-sun-400);
  overflow-x: auto;
}

.formula pre {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.875rem;
  line-height: 1.75;
  color: #dbe6ff;
  white-space: pre;
}

.formula .k { color: var(--be-sun-300); }
.formula .c { color: #7f92bb; font-style: italic; }

.formula__title {
  display: block;
  margin-bottom: 0.6rem;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: #8fa6d8;
}

/* --------------------------------------------------------------------------
   Callout
   -------------------------------------------------------------------------- */
.callout {
  display: flex;
  gap: var(--space-sm);
  padding: var(--space-md);
  margin: var(--space-md) 0;
  background: var(--accent-soft);
  border-radius: var(--radius-md);
  border-left: 4px solid var(--be-blue-500);
  font-size: 0.9375rem;
}

.callout__icon {
  flex-shrink: 0;
  width: 1.35rem;
  height: 1.35rem;
  margin-top: 0.15rem;
  color: var(--be-blue-600);
}

/* Judul callout memakai skala h4 apa pun tingkat semantiknya. Tingkat
   heading ditentukan posisinya di dalam dokumen, bukan ukurannya. */
.callout :is(h2, h3, h4) {
  margin-bottom: 0.3rem;
  font-family: var(--font-ui);
  font-weight: 800;
  font-size: var(--text-h4);
  line-height: var(--leading-snug);
  letter-spacing: var(--track-snug);
}
.callout p { color: var(--ink-600); }
.callout p + p { margin-top: 0.6rem; }

.callout--warn { background: var(--warn-soft); border-left-color: var(--be-sun-500); }
.callout--warn .callout__icon { color: var(--be-sun-700); }
.callout--danger { background: var(--danger-soft); border-left-color: var(--danger); }
.callout--danger .callout__icon { color: var(--danger); }
.callout--ok { background: var(--ok-soft); border-left-color: var(--ok); }
.callout--ok .callout__icon { color: var(--ok); }

/* --------------------------------------------------------------------------
   Akordeon (FAQ)
   -------------------------------------------------------------------------- */
.accordion {
  border-top: 1px solid var(--line);
}

.accordion__item { border-bottom: 1px solid var(--line); }

.accordion__btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  width: 100%;
  padding: 1.15rem 0.25rem;
  background: none;
  border: 0;
  text-align: left;
  font-family: var(--font-ui);
  font-size: var(--text-h4);
  font-weight: 700;
  letter-spacing: var(--track-snug);
  color: var(--ink-900);
  transition: color var(--dur-fast) var(--ease-out);
}

.accordion__btn:hover { color: var(--be-blue-700); }

.accordion__sign {
  position: relative;
  flex-shrink: 0;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  transition: background-color var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out);
}

.accordion__sign::before,
.accordion__sign::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0.7rem;
  height: 2px;
  border-radius: 2px;
  background: var(--ink-700);
  translate: -50% -50%;
  transition: transform var(--dur) var(--ease-out), background-color var(--dur) var(--ease-out);
}

.accordion__sign::after { transform: rotate(90deg); }

.accordion__btn[aria-expanded='true'] .accordion__sign {
  background: var(--be-blue-700);
  border-color: var(--be-blue-700);
  transform: rotate(180deg);
}

.accordion__btn[aria-expanded='true'] .accordion__sign::before,
.accordion__btn[aria-expanded='true'] .accordion__sign::after { background: #fff; }
.accordion__btn[aria-expanded='true'] .accordion__sign::after { transform: rotate(0deg); }

.accordion__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-slow) var(--ease-out);
}

.accordion__panel[data-open='true'] { grid-template-rows: 1fr; }

.accordion__inner {
  overflow: hidden;
  color: var(--text-muted);
}

.accordion__panel[data-open='true'] .accordion__inner { padding-bottom: 1.35rem; }
.accordion__inner > * + * { margin-top: 0.75rem; }
.accordion__inner p { max-width: 68ch; }

/* --------------------------------------------------------------------------
   Formulir
   -------------------------------------------------------------------------- */
.field { display: flex; flex-direction: column; gap: 0.4rem; }

.field label {
  font-family: var(--font-ui);
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--ink-800, var(--ink-700));
}

.field .hint {
  font-size: var(--text-sm);
  color: var(--text-faint);
  line-height: 1.45;
}

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 0.7rem 0.9rem;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  font-size: 1rem;
  transition: border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--be-blue-500);
  box-shadow: 0 0 0 3px rgba(27, 91, 232, 0.16);
}

.field textarea { resize: vertical; min-height: 7rem; }

.field input[aria-invalid='true'],
.field select[aria-invalid='true'],
.field textarea[aria-invalid='true'] {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px rgba(176, 32, 32, 0.12);
}

.error {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--danger);
}

/* Menahan tinggi baris agar formulir tidak melompat saat pesan muncul.
   Hanya berlaku di dalam .field: di luar itu galatnya bukan bagian dari
   sebuah isian. */
.field .error { min-height: 1.2em; }

/* Galat yang berdiri di luar .field. Kotak centang persetujuan menaruh
   labelnya satu baris dengan kotaknya, jadi pesannya harus menjadi blok
   sendiri di bawah keduanya. */
.error--standalone {
  display: block;
  margin-top: var(--space-3xs);
}

.field--inline { display: grid; grid-template-columns: auto 1fr; gap: 0.6rem; align-items: start; }
.field--inline input[type='checkbox'] { width: 1.1rem; height: 1.1rem; margin-top: 0.25rem; accent-color: var(--be-blue-700); }
.field--inline label { font-weight: 400; font-family: var(--font-body); font-size: var(--text-sm); color: var(--text-muted); }

/* Keterangan "opsional" yang menempel di label wajib. */
.label-optional { font-weight: 400; color: var(--text-faint); }

/* Nilai berjalan di samping label, mis. persentase pada penggeser. */
.field output {
  font-family: var(--font-mono);
  color: var(--be-blue-700);
}

/* Penggeser tidak boleh mewarisi kotak isian dari .field input. */
.field input[type='range'] {
  padding: 0;
  border: 0;
  accent-color: var(--be-blue-700);
}

/* --------------------------------------------------------------------------
   Pilihan radio yang tampil sebagai kartu, bukan bulatan telanjang.
   Ditempatkan setelah .field--inline karena menimpa align-items-nya.
   -------------------------------------------------------------------------- */
.choice-group {
  border: 0;
  padding: 0;
  margin: 0 0 var(--space-md);
}

.choice-group legend { margin-bottom: 0.65rem; }

.choice {
  align-items: center;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.choice input[type='radio'] {
  width: 1.1rem;
  height: 1.1rem;
  margin: 0;
  accent-color: var(--be-blue-700);
}

.choice__label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-note);
  color: var(--ink-900);
}

/* Bidang sentuh kontrol formulir. Lihat catatan di dekat `.btn--sm`.

   Blok ini WAJIB berada setelah aturan dasar `.field--inline input` dan
   `.field input[type='range']` di atas. Media query tidak menambah
   spesifisitas, jadi menaruhnya lebih awal membuat aturan dasar yang menang —
   kotak centang tetap 17,6px di perangkat sentuh dan perbaikannya diam-diam
   tidak berlaku. */
@media (pointer: coarse) {
  /* 1,5rem = 24px tepat, ambang WCAG 2.2 SC 2.5.8. Kotak ini punya <label for>
     yang ikut dapat disentuh, jadi sasaran efektifnya sudah jauh lebih besar dan
     kriteria itu sebenarnya terpenuhi lewat pengecualian label. Ukurannya tetap
     dinaikkan sampai lulus berdiri sendiri: persetujuan ini syarat kirim
     formulir, dan tidak ada gunanya bergantung pada pengecualian di satu-satunya
     kendali yang memblokir konversi bila terlewat. */
  .field--inline input[type='checkbox'] {
    width: 1.5rem;
    height: 1.5rem;
    margin-top: 0;
  }

  /* Radio jenis sistem duduk di dalam kartu <label> yang seluruhnya dapat
     disentuh, jadi sasarannya tidak pernah bermasalah. Yang disamakan di sini
     hanya ukuran gambarnya, supaya bulatan dan kotak centang tidak tampil
     dengan dua bobot berbeda di formulir yang sama. */
  .choice input[type='radio'] {
    width: 1.375rem;
    height: 1.375rem;
  }

  /* Yang membesar kotak sentuhnya, bukan gagangnya: gagang tetap di tengah dan
     tampilannya tidak berubah, tetapi jari tidak lagi harus mengenai pita
     setinggi 16px. */
  .field input[type='range'] { min-height: 44px; }
}

/* --------------------------------------------------------------------------
   Daftar kanal kontak — ikon bulat, judul, lalu nilainya.
   Sebelumnya dirakit dari 15 atribut style= yang mengulang pola yang sama
   tiga kali di halaman kontak.
   -------------------------------------------------------------------------- */
.channels {
  list-style: none;
  padding: 0;
  margin-top: var(--space-sm);
}

.channels li {
  display: flex;
  gap: var(--space-xs);
  align-items: flex-start;
  margin-top: var(--space-xs);
}

.channels .card__icon {
  width: 2.25rem;
  height: 2.25rem;
  margin: 0;
  flex-shrink: 0;
}

.channels .card__icon svg { width: 1.1rem; height: 1.1rem; }

.channels strong {
  display: block;
  color: var(--ink-900);
}

.channels__value { color: var(--text-muted); }

/* Tinggi sentuh nomor telepon dan alamat surel pada halaman kontak.

   Ini kanal kontak utama halaman itu, dan tingginya hanya ~19px. Berbeda dari
   tautan di dalam kalimat, keduanya berdiri sendiri sebagai sasaran — jadi
   pengecualian WCAG 2.2 SC 2.5.8 untuk tautan inline tidak berlaku di sini.

   Hanya <a> yang dinaikkan, bukan seluruh baris: alamat kantor di baris ketiga
   bukan tautan dan tidak perlu ikut melar. */
@media (pointer: coarse) {
  .channels a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

/* Nama badan hukum memimpin blok alamat, seperti di footer.

   Bobotnya 600, satu tingkat di bawah <strong> label kanal di atasnya: label
   itu yang menerangkan jenis kanalnya, dan nama entitas tidak boleh terbaca
   sebagai label kedua. Tetap di atas .channels__value yang meredup, sehingga
   urutannya kanal → entitas → alamat. */
.channels__legal {
  display: block;
  font-weight: 600;
  color: var(--ink-800);
}

/* Keterangan tambahan di bawah nilai, mis. wilayah layanan di bawah alamat. */
.channels__note {
  display: block;
  margin-top: 0.35rem;
  color: var(--text-faint);
  font-size: var(--text-sm);
}

/* Honeypot anti-spam — disembunyikan dari manusia, terlihat oleh bot */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-status {
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--radius-sm);
  font-size: 0.9375rem;
  font-weight: 600;
}

.form-status[data-state='ok'] { background: var(--ok-soft); color: var(--ok); }
.form-status[data-state='err'] { background: var(--danger-soft); color: var(--danger); }
.form-status[hidden] { display: none; }

/* --------------------------------------------------------------------------
   Elemen mengambang: WhatsApp & cookie
   -------------------------------------------------------------------------- */
.floating-cta {
  position: fixed;
  right: clamp(0.9rem, 2vw, 1.6rem);
  bottom: clamp(0.9rem, 2vw, 1.6rem);
  z-index: var(--z-toast);
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.8rem 1.15rem;
  background: var(--wa);
  color: #fff;
  border-radius: var(--radius-pill);
  font-family: var(--font-ui);
  font-weight: 700;
  /* 19px, bukan 15px. Ukuran ini dinaikkan saat hijaunya masih #1faa54 dan
     hanya lolos lewat ambang teks besar. Setelah --wa digelapkan, rasionya
     4,70:1 dan lolos ambang teks biasa juga, jadi ukurannya tidak lagi wajib.
     Dipertahankan karena tombol mengambang memang pantas berlabel besar. */
  font-size: 1.1875rem;
  text-decoration: none;
  box-shadow: 0 14px 30px -12px rgba(20, 133, 68, 0.7);
  transition: transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}

.floating-cta:hover {
  color: #fff;
  transform: translateY(-3px) scale(1.02);
  box-shadow: 0 20px 40px -14px rgba(20, 133, 68, 0.8);
}

.floating-cta svg { width: 1.35rem; height: 1.35rem; }

@media (max-width: 560px) {
  .floating-cta__text { display: none; }
  .floating-cta { padding: 0.85rem; }
}

.cookie-bar {
  position: fixed;
  left: clamp(0.75rem, 2vw, 1.5rem);
  bottom: clamp(0.75rem, 2vw, 1.5rem);
  z-index: var(--z-toast);
  max-width: 27rem;
  padding: var(--space-md);
  background: var(--paper);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  font-size: var(--text-sm);
  color: var(--text-muted);
  transform: translateY(140%);
  transition: transform var(--dur-slow) var(--ease-out);
}

.cookie-bar.is-shown { transform: translateY(0); }

/* Kedua elemen mengambang ini berada di lapis --z-toast (300), di atas laci
   navigasi (--z-drawer, 200). Selama laci terbuka keduanya menutupi butir menu
   — di viewport 390px bilah cookie menutup empat baris sekaligus. Urutan lapis
   itu benar untuk keadaan biasa dan sengaja tidak diubah; yang dilakukan di
   sini adalah menyingkirkan keduanya selama laci memegang layar, lalu
   mengembalikannya begitu laci ditutup. */
body.is-locked .floating-cta,
body.is-locked .cookie-bar {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--dur) var(--ease-out), visibility var(--dur);
}
.cookie-bar[hidden] { display: none; }
.cookie-bar h4 { margin-bottom: 0.35rem; color: var(--ink-900); }
.cookie-bar .btn-row { margin-top: var(--space-sm); }

@media (max-width: 560px) {
  .cookie-bar { right: clamp(0.75rem, 2vw, 1.5rem); max-width: none; bottom: 5.5rem; }
}

/* --------------------------------------------------------------------------
   Animasi scroll reveal
   -------------------------------------------------------------------------- */
/* Keadaan tersembunyi HANYA berlaku bila JavaScript aktif.
   Kelas .has-js dipasang oleh assets/js/has-js.js — skrip sinkron di <head>,
   bukan main.js yang ber-defer. Tanpa ini, kegagalan memuat JS (jaringan
   buruk, pemblokir skrip) akan membuat seluruh konten ber-data-reveal tetap
   opacity 0 alias tidak terlihat sama sekali. */
.has-js [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

.has-js [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .has-js [data-reveal] { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   Breadcrumb
   -------------------------------------------------------------------------- */
.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: center;
  list-style: none;
  padding: 0;
  margin-bottom: var(--space-sm);
  font-size: var(--text-sm);
  color: var(--text-faint);
}

.breadcrumb li { margin: 0; display: flex; align-items: center; gap: 0.4rem; }
.breadcrumb li + li::before { content: '/'; color: var(--line-strong); }
.breadcrumb a { color: inherit; text-decoration: none; }
.breadcrumb a:hover { color: var(--accent); }

/* ===== assets/css/sections.css ===== */
/* ==========================================================================
   Barokah Energy — Section spesifik
   ========================================================================== */

/* --------------------------------------------------------------------------
   Hero beranda
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  padding-block: clamp(3.5rem, 2rem + 6vw, 7rem) clamp(3rem, 2rem + 4vw, 5.5rem);
  background: var(--grad-night);
  color: #fff;
  overflow: hidden;
  isolation: isolate;
}

/* Berkas sinar diagonal — motif tanda tangan visual */
.hero__rays {
  position: absolute;
  inset: -20% -10%;
  z-index: -1;
  background:
    linear-gradient(108deg, transparent 30%, rgba(48, 179, 255, 0.16) 30.5%, rgba(48, 179, 255, 0.16) 34%, transparent 34.5%),
    linear-gradient(108deg, transparent 46%, rgba(255, 209, 0, 0.14) 46.4%, rgba(255, 209, 0, 0.14) 48.6%, transparent 49%),
    linear-gradient(108deg, transparent 68%, rgba(48, 179, 255, 0.1) 68.3%, rgba(48, 179, 255, 0.1) 73%, transparent 73.4%);
  animation: rayDrift 26s var(--ease-in-out) infinite alternate;
  pointer-events: none;
}

.hero__glow {
  position: absolute;
  top: -28%;
  right: -14%;
  z-index: -1;
  width: min(50rem, 88vw);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 165, 31, 0.34) 0%, rgba(255, 209, 0, 0.1) 38%, transparent 68%);
  filter: blur(6px);
  pointer-events: none;
}

@keyframes rayDrift {
  from { transform: translateX(-2.5%); }
  to { transform: translateX(2.5%); }
}

/* --------------------------------------------------------------------------
   Lapisan foto hero (opsional)

   Aktif hanya bila <div class="hero__media"> ada di dalam .hero. Selama blok
   itu belum dipasang, seluruh aturan di bawah tidak mengenai apa pun dan hero
   tetap tampil dengan --grad-night seperti sebelumnya. Lihat catatan aktivasi
   di tools/content/index.html dan docs/brief-visual.md bagian A1.

   Urutan lapisan di dalam .hero (yang punya isolation: isolate):
     -3  .hero__media      foto
     -2  .hero__media::after  scrim
     -1  .hero__rays, .hero__glow
      0  .hero__grid       teks dan panel
   -------------------------------------------------------------------------- */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: -3;
  overflow: hidden;
  pointer-events: none;
}

.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Foto A1 menempatkan langit di dua pertiga atas dan array di sepertiga
     bawah. Titik 65 % menjaga panel tetap terlihat saat hero dipotong pendek
     di layar lebar. Setel ulang bila komposisi fotonya berbeda. */
  object-position: center 65%;
}

/* Scrim. Bukan sekadar penggelap: tanpa ini teks hero jatuh di bawah 4,5:1
   begitu latar memuat area yang terang.

   Nilai di bawah diturunkan dari versi sebelumnya (0,94 / 0,86 / 0,72) agar
   video latar benar-benar terlihat. Penurunan itu tidak dikira-kira, tetapi
   diukur terhadap luminans asli hero-header.mp4 memakai ffmpeg signalstats:

     kolom teks kiri   YAVG maksimum 125,9  (≈ RGB 128)
     area panel kanan  YAVG maksimum 140,7  (≈ RGB 145)

   Terhadap luminans itu, teks paling redup di kolom kiri (.hero__trust,
   #9fb3de, ukuran kecil sehingga wajib 4,5:1) berada pada ±5,9:1. Judul dan
   lede jauh di atasnya.

   Dua hal yang wajib diperiksa ulang bila salah satu berubah:
     1. Mengganti berkas video. Ukur ulang dengan signalstats; video yang
        lebih terang menuntut alpha lebih tinggi.
     2. Meredupkan warna teks hero mana pun. #9fb3de adalah batasnya.

   Panel kanan tidak lagi bergantung pada scrim ini; ia membawa latar gelap
   sendiri. Lihat catatan di .hero__panel. */
.hero__media::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(100deg,
      rgba(3, 15, 63, 0.68) 0%,
      rgba(3, 15, 63, 0.58) 45%,
      rgba(4, 26, 110, 0.40) 100%),
    linear-gradient(to top,
      rgba(3, 15, 63, 0.32) 0%,
      rgba(3, 15, 63, 0) 60%);
}

/* Di bawah 1000px hero__grid jatuh ke satu kolom dan teks membentang penuh,
   jadi sisi kanan tidak lagi tertutup panel. Scrim tetap lebih rapat daripada
   versi lebar karena bagian video mana yang terpotong tidak dapat diramalkan.

   Diukur terhadap area paling terang di seluruh hero-header.mp4 (YAVG 140,7),
   bukan hanya kolom kiri: pada alpha 0,72 teks terkecil dan paling redup
   (.hero__trust #9fb3de) berada pada 5,8:1, dengan cadangan yang sehat di
   atas 4,5:1. */
@media (max-width: 1000px) {
  .hero__media::after {
    background:
      linear-gradient(180deg,
        rgba(3, 15, 63, 0.72) 0%,
        rgba(3, 15, 63, 0.70) 60%,
        rgba(4, 26, 110, 0.66) 100%);
  }
}

.hero__grid {
  position: relative;
  display: grid;
  /* Dilebarkan dari 1.08/0.92: judul serif butuh ukuran baris lebih panjang
     agar dua baris yang ditulis penulis tidak pecah. Panel monitoring di
     kanan tetap ±386px, cukup untuk grid pembacaan dua kolomnya. */
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.75fr);
  gap: var(--space-2xl);
  align-items: center;
}

@media (max-width: 1000px) {
  .hero__grid { grid-template-columns: minmax(0, 1fr); gap: var(--space-xl); }
}

.hero__badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.9rem 0.4rem 0.45rem;
  margin-bottom: var(--space-md);
  background: rgba(255, 255, 255, 0.09);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  color: #d6e3ff;
  backdrop-filter: blur(8px);
}

.hero__badge b {
  padding: 0.15rem 0.55rem;
  border-radius: var(--radius-pill);
  background: var(--grad-sun);
  color: var(--ink-900);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
}

.hero h1 {
  font-size: var(--text-mega);
  color: #fff;
}

.hero h1 .accent {
  background: var(--grad-sun);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.hero__lede {
  margin-top: var(--space-md);
  max-width: 52ch;
  font-size: var(--text-lead);
  color: #bccbef;
}

.hero__actions { margin-top: var(--space-lg); }

.hero__trust {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.35rem;
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  list-style: none;
  padding-left: 0;
  font-size: var(--text-sm);
  color: #9fb3de;
}

.hero__trust li { display: flex; align-items: center; gap: 0.45rem; margin: 0; }
.hero__trust svg { width: 1em; height: 1em; color: var(--be-sun-300); flex-shrink: 0; }

/* --- Panel monitoring imitasi di sisi kanan hero --- */
/* Latar panel sengaja gelap, bukan putih transparan seperti sebelumnya.

   Lapisan putih 6% MENAIKKAN luminans latar, dan itu mematikan label
   readout (#8fa6d8, ukuran kecil, wajib 4,5:1): terhadap video latar ia
   hanya mencapai 3,61:1 — gagal, bahkan pada scrim lama yang jauh lebih
   pekat. Dengan navy 55% angkanya menjadi ±5,0:1.

   Efek sampingnya menguntungkan: karena panel kini menjaga kontrasnya
   sendiri, scrim di belakangnya boleh jauh lebih ringan dan video terlihat.
   Blur tetap dipertahankan, jadi kesan kaca tidak hilang. */
.hero__panel {
  position: relative;
  padding: var(--space-md);
  background: rgba(3, 15, 63, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--radius-xl);
  backdrop-filter: blur(18px);
  box-shadow: 0 40px 80px -40px rgba(0, 0, 0, 0.8);
}

.hero__panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding-bottom: var(--space-sm);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

.hero__panel-title {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: #9fb3de;
}

.live-dot {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: #7ee2a8;
}

.live-dot::before {
  content: '';
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: #4ade80;
  box-shadow: 0 0 0 0 rgba(74, 222, 128, 0.7);
  animation: pulse 2.4s var(--ease-out) infinite;
}

@keyframes pulse {
  70% { box-shadow: 0 0 0 8px rgba(74, 222, 128, 0); }
  100% { box-shadow: 0 0 0 0 rgba(74, 222, 128, 0); }
}

.hero__readout {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-sm);
  padding-block: var(--space-md);
}

.readout__label {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #8fa6d8;
}

.readout__value {
  font-family: var(--font-ui);
  font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2.1rem);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: var(--track-tight);
  font-variant-numeric: tabular-nums;
  color: #fff;
}

.readout__value small {
  font-family: var(--font-mono);
  font-size: 0.45em;
  font-weight: 500;
  color: #9fb3de;
  letter-spacing: 0;
}

.readout__value.is-sun {
  background: var(--grad-sun);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Grafik kurva produksi harian (bar sederhana, CSS murni) */
.daychart {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 5.5rem;
  padding-top: var(--space-sm);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.daychart__bar {
  flex: 1;
  min-width: 0;
  border-radius: 2px 2px 0 0;
  background: linear-gradient(180deg, var(--be-sun-300) 0%, var(--be-sun-600) 100%);
  height: var(--h, 10%);
  opacity: 0.9;
  transform-origin: bottom;
  animation: growBar 900ms var(--ease-out) backwards;
  animation-delay: var(--d, 0ms);
}

/* Kurva produksi satu hari — ilustrasi tetap, bukan data yang berubah.
   Tingginya ditulis di sini alih-alih sebagai style= per batang: 24 atribut
   inline pada satu grafik sendirian memaksa CSP membuka 'unsafe-inline'.
   Jedanya bertambah 30ms tiap batang, memberi efek matahari terbit. */
.daychart__bar:nth-child(1)  { --h: 8%;   --d: 0ms; }
.daychart__bar:nth-child(2)  { --h: 7%;   --d: 30ms; }
.daychart__bar:nth-child(3)  { --h: 7%;   --d: 60ms; }
.daychart__bar:nth-child(4)  { --h: 9%;   --d: 90ms; }
.daychart__bar:nth-child(5)  { --h: 14%;  --d: 120ms; }
.daychart__bar:nth-child(6)  { --h: 28%;  --d: 150ms; }
.daychart__bar:nth-child(7)  { --h: 46%;  --d: 180ms; }
.daychart__bar:nth-child(8)  { --h: 64%;  --d: 210ms; }
.daychart__bar:nth-child(9)  { --h: 82%;  --d: 240ms; }
.daychart__bar:nth-child(10) { --h: 94%;  --d: 270ms; }
.daychart__bar:nth-child(11) { --h: 100%; --d: 300ms; }
.daychart__bar:nth-child(12) { --h: 96%;  --d: 330ms; }
.daychart__bar:nth-child(13) { --h: 85%;  --d: 360ms; }
.daychart__bar:nth-child(14) { --h: 68%;  --d: 390ms; }
.daychart__bar:nth-child(15) { --h: 44%;  --d: 420ms; }
.daychart__bar:nth-child(16) { --h: 22%;  --d: 450ms; }
.daychart__bar:nth-child(17) { --h: 10%;  --d: 480ms; }
.daychart__bar:nth-child(18) { --h: 26%;  --d: 510ms; }
.daychart__bar:nth-child(19) { --h: 34%;  --d: 540ms; }
.daychart__bar:nth-child(20) { --h: 30%;  --d: 570ms; }
.daychart__bar:nth-child(21) { --h: 22%;  --d: 600ms; }
.daychart__bar:nth-child(22) { --h: 16%;  --d: 630ms; }
.daychart__bar:nth-child(23) { --h: 11%;  --d: 660ms; }
.daychart__bar:nth-child(24) { --h: 9%;   --d: 690ms; }

.daychart__bar.is-night {
  background: linear-gradient(180deg, var(--be-blue-400) 0%, var(--be-blue-800) 100%);
  opacity: 0.65;
}

@keyframes growBar {
  from { transform: scaleY(0.04); opacity: 0; }
}

.daychart__axis {
  display: flex;
  justify-content: space-between;
  margin-top: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.625rem;
  /* #7f92bb hanya 4,07:1 di sudut paling terang --grad-night; pada 10px
     label jam ini butuh 4,5:1. #93a5cc memberi 5,13:1. */
  color: #93a5cc;
}

/* --------------------------------------------------------------------------
   Bar statistik
   -------------------------------------------------------------------------- */
.statbar {
  border-block: 1px solid var(--line);
  background: var(--paper-soft);
}

.statbar__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-md);
  padding-block: var(--space-xl);
}

@media (max-width: 860px) {
  .statbar__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-lg) var(--space-md); }
}

/* --------------------------------------------------------------------------
   Bento — ekosistem sistem
   -------------------------------------------------------------------------- */
.bento {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--space-sm);
}

.bento > * { grid-column: span 2; }
.bento__wide { grid-column: span 3; }
.bento__lg { grid-column: span 4; }
.bento__hero { grid-column: span 6; }

@media (min-width: 961px) {
  .bento__hero {
    grid-column: span 6;
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    gap: var(--space-lg);
    align-items: center;
    padding: var(--space-xl);
  }
}

@media (max-width: 960px) {
  .bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .bento > *,
  .bento__wide,
  .bento__lg,
  .bento__hero { grid-column: span 2; }
}

@media (max-width: 620px) {
  .bento { grid-template-columns: minmax(0, 1fr); }
  .bento > *,
  .bento__wide,
  .bento__lg,
  .bento__hero { grid-column: span 1; }
}

/* --------------------------------------------------------------------------
   Diagram alur energi (4 tahap PLTS)
   -------------------------------------------------------------------------- */
.flow {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-sm);
  counter-reset: flowstep;
}

@media (max-width: 900px) { .flow { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .flow { grid-template-columns: minmax(0, 1fr); } }

.flow__node {
  position: relative;
  padding: var(--space-md);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}

/* Panah penghubung antar tahap */
.flow__node:not(:last-child)::after {
  content: '';
  position: absolute;
  top: 50%;
  right: calc(var(--space-sm) * -1);
  width: var(--space-sm);
  height: 2px;
  translate: 0 -50%;
  background: linear-gradient(90deg, var(--be-blue-300), var(--be-sun-400));
}

@media (max-width: 900px) {
  .flow__node:nth-child(2n)::after,
  .flow__node:last-child::after { display: none; }
}

@media (max-width: 560px) {
  .flow__node::after { display: none !important; }
}

.flow__num {
  counter-increment: flowstep;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  margin-bottom: var(--space-sm);
  border-radius: var(--radius-sm);
  background: var(--grad-brand);
  color: #fff;
  font-family: var(--font-mono);
  font-size: 0.875rem;
  font-weight: 600;
}

.flow__num::before { content: counter(flowstep); }

.flow__node h3 { font-size: var(--text-h4); margin-bottom: 0.4rem; }
.flow__node p { font-size: 0.9375rem; color: var(--text-muted); }

/* --------------------------------------------------------------------------
   Linimasa proses proyek
   -------------------------------------------------------------------------- */
.timeline { list-style: none; padding: 0; margin: 0; }

.timeline__item {
  position: relative;
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr);
  gap: var(--space-md);
  padding-bottom: var(--space-lg);
  margin: 0;
}

.timeline__item:not(:last-child)::before {
  content: '';
  position: absolute;
  top: 3.5rem;
  bottom: 0;
  left: 1.7rem;
  width: 2px;
  background: linear-gradient(180deg, var(--be-blue-200), var(--line));
}

.timeline__marker {
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: var(--radius-md);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  font-family: var(--font-mono);
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--be-blue-700);
}

.timeline__item:hover .timeline__marker {
  background: var(--grad-brand);
  border-color: transparent;
  color: #fff;
}

.timeline__body { padding-top: 0.35rem; }
.timeline__body :is(h2, h3) {
  margin-bottom: 0.35rem;
  font-family: var(--font-ui);
  font-weight: 800;
  font-size: var(--text-h3);
  line-height: var(--leading-snug);
  letter-spacing: var(--track-tight);
}
.timeline__body p { color: var(--text-muted); }

.timeline__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.6rem;
}

@media (max-width: 560px) {
  .timeline__item { grid-template-columns: 2.75rem minmax(0, 1fr); gap: var(--space-sm); }
  .timeline__marker { width: 2.75rem; height: 2.75rem; font-size: 1rem; }
  .timeline__item:not(:last-child)::before { top: 2.75rem; left: 1.32rem; }
}

/* --------------------------------------------------------------------------
   Hero halaman dalam
   -------------------------------------------------------------------------- */
.page-hero {
  position: relative;
  padding-block: clamp(2.5rem, 1.8rem + 3.4vw, 4.5rem) clamp(2.5rem, 1.8rem + 3vw, 4rem);
  background: var(--grad-dawn);
  color: #fff;
  overflow: hidden;
  isolation: isolate;
}

.page-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(108deg, transparent 56%, rgba(255, 209, 0, 0.13) 56.4%, rgba(255, 209, 0, 0.13) 60%, transparent 60.4%);
  pointer-events: none;
}

.page-hero h1 { color: #fff; max-width: 20ch; }

.page-hero__lede {
  margin-top: var(--space-md);
  max-width: 58ch;
  font-size: var(--text-lead);
  color: #c8d7ff;
}

/* #c8d7ff dipilih agar tetap ≥ 4,5:1 terhadap stop paling terang
   pada --grad-dawn. Nada yang lebih redup (mis. #9fb3de) gagal di
   sudut terang gradien. */
.page-hero .breadcrumb,
.page-hero .breadcrumb a { color: #c8d7ff; }
.page-hero .breadcrumb a:hover { color: var(--be-sun-300); }
.page-hero .breadcrumb li + li::before { color: rgba(255, 255, 255, 0.45); }
.page-hero .eyebrow { color: #c8d7ff; }

/* Varian terpusat, dipakai halaman tanpa remah roti dan tanpa isi lanjutan
   di sebelahnya — sejauh ini hanya 404. Satu kelas menggantikan enam atribut
   style= yang sebelumnya memusatkan tiap elemen satu per satu. */
.page-hero--center {
  padding-block: clamp(4rem, 3rem + 6vw, 8rem);
  text-align: center;
}

.page-hero--center .eyebrow { justify-content: center; }
.page-hero--center h1 { max-width: 100%; margin-inline: auto; }
.page-hero--center .page-hero__lede { margin-inline: auto; }

.page-hero--center .btn-row {
  margin-top: var(--space-lg);
  justify-content: center;
}

/* --------------------------------------------------------------------------
   Split media/teks
   -------------------------------------------------------------------------- */
.split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2xl);
  align-items: center;
}

@media (max-width: 900px) { .split { grid-template-columns: minmax(0, 1fr); gap: var(--space-xl); } }

.split--reverse > :first-child { order: 2; }
@media (max-width: 900px) { .split--reverse > :first-child { order: 0; } }

.prose > * + * { margin-top: var(--space-md); }
.prose h2 { margin-top: var(--space-xl); }
.prose h3 { margin-top: var(--space-lg); }
.prose ul { color: var(--text-muted); }
.prose > p { color: var(--text-muted); }
.prose > p:first-of-type { font-size: var(--text-lead); color: var(--ink-600); }

/* Daftar centang */
.checklist { list-style: none; padding: 0; }

.checklist li {
  position: relative;
  padding-left: 1.9rem;
  margin-top: 0.65rem;
  color: var(--text-muted);
}

.checklist li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.42em;
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 50%;
  background: var(--ok-soft) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230e7a4a' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center / 0.72rem no-repeat;
}

.checklist--cross li::before {
  background: var(--danger-soft) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23b02020' stroke-width='3.4' stroke-linecap='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E") center / 0.66rem no-repeat;
}

/* --------------------------------------------------------------------------
   Pita CTA penutup
   -------------------------------------------------------------------------- */
.cta-band {
  position: relative;
  padding-block: var(--space-2xl);
  background: var(--grad-dawn);
  color: #fff;
  overflow: hidden;
  isolation: isolate;
}

.cta-band::before {
  content: '';
  position: absolute;
  bottom: -60%;
  left: -10%;
  z-index: -1;
  width: 38rem;
  height: 38rem;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 209, 0, 0.2) 0%, transparent 62%);
  pointer-events: none;
}

.cta-band__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) auto;
  gap: var(--space-lg);
  align-items: center;
}

@media (max-width: 820px) {
  .cta-band__inner { grid-template-columns: minmax(0, 1fr); }
}

.cta-band h2 { color: #fff; max-width: 18ch; }
.cta-band p { margin-top: var(--space-sm); max-width: 52ch; color: #c8d7ff; }

/* --------------------------------------------------------------------------
   Kalkulator
   -------------------------------------------------------------------------- */
.calc {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: var(--space-lg);
  align-items: start;
}

@media (max-width: 980px) { .calc { grid-template-columns: minmax(0, 1fr); } }

.calc__form {
  padding: var(--space-lg);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.calc__form .field + .field,
.calc__form .field-group + .field-group { margin-top: var(--space-md); }

/* Judul panel formulir selalu setingkat h3, bukan h2 penuh: ia bersaing
   dengan h1 halaman dan tidak boleh menang. */
.calc__form h2 {
  font-size: var(--text-h3);
  margin-bottom: var(--space-2xs);
}

.field-group {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-sm);
}

@media (max-width: 520px) { .field-group { grid-template-columns: minmax(0, 1fr); } }

.calc__result {
  position: sticky;
  top: calc(var(--header-h) + 1.25rem);
  padding: var(--space-lg);
  background: var(--grad-night);
  border-radius: var(--radius-lg);
  color: #fff;
  overflow: hidden;
}

@media (max-width: 980px) { .calc__result { position: static; } }

.calc__result h3 { color: #fff; font-size: var(--text-h3); }

/* Kalimat pembuka panel hasil: satu tingkat di bawah judul, di atas catatan. */
.result__lede {
  margin-top: 0.4rem;
  font-size: var(--text-note);
  color: #a9bbdd;
}

.result-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-md);
  margin-block: var(--space-md);
  padding-block: var(--space-md);
  border-block: 1px solid rgba(255, 255, 255, 0.14);
}

@media (max-width: 400px) { .result-grid { grid-template-columns: minmax(0, 1fr); } }

.result__label {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #8fa6d8;
}

.result__value {
  font-family: var(--font-ui);
  font-size: clamp(1.35rem, 1.1rem + 1vw, 1.85rem);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: var(--track-tight);
  font-variant-numeric: tabular-nums;
  color: #fff;
}

.result__value small {
  font-family: var(--font-mono);
  font-size: 0.5em;
  font-weight: 500;
  color: #9fb3de;
}

.result__value.is-sun {
  background: var(--grad-sun);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.result__note {
  font-size: var(--text-sm);
  color: #a9bbdd;
  line-height: 1.55;
}

.result__note a { color: var(--be-sun-300); }
.result__note strong { color: #fff; }

/* Versi daftar butir; butuh ruang untuk penanda di kiri. */
ul.result__note { padding-left: 1.1rem; }

/* Bar cakupan konsumsi */
.coverage {
  margin-block: var(--space-md);
}

.coverage__track {
  position: relative;
  height: 0.85rem;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.12);
  overflow: hidden;
}

.coverage__fill {
  height: 100%;
  width: 0%;
  border-radius: var(--radius-pill);
  background: var(--grad-sun);
  transition: width var(--dur-slow) var(--ease-out);
}

.coverage__legend {
  display: flex;
  justify-content: space-between;
  margin-top: 0.45rem;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: #8fa6d8;
}

/* Angka cakupan yang berjalan saat hasil dihitung. */
.coverage__legend strong { color: var(--be-sun-300); }

/* --------------------------------------------------------------------------
   Glosarium
   -------------------------------------------------------------------------- */
.glossary {
  display: grid;
  gap: var(--space-sm);
}

.glossary__item {
  display: grid;
  grid-template-columns: minmax(9rem, 15rem) minmax(0, 1fr);
  gap: var(--space-md);
  padding: var(--space-md);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}

@media (max-width: 700px) {
  .glossary__item { grid-template-columns: minmax(0, 1fr); gap: 0.35rem; }
}

.glossary__term {
  font-family: var(--font-ui);
  font-weight: 800;
  color: var(--ink-900);
  letter-spacing: var(--track-snug);
}

.glossary__term small {
  display: block;
  margin-top: 0.15rem;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--text-faint);
  letter-spacing: 0.03em;
}

.glossary__def { color: var(--text-muted); font-size: 0.9375rem; }
.glossary__def em { color: var(--ink-600); font-style: normal; font-weight: 600; }

/* ===== assets/css/media.css ===== */
/* ===========================================================================
   MEDIA — foto dan video latar

   Dipisah dari sections.css karena berkas itu sudah mendekati batas layak
   baca. Semua aturan di sini bersifat presentasional dan tidak mengubah
   perilaku skrip mana pun.

   Dua prinsip yang mengikat:

   1. Video di situs ini selalu dekoratif. Tidak ada informasi yang hanya
      tersedia lewat video, sehingga aman diberi aria-hidden dan aman pula
      bila tidak pernah diputar.
   2. Poster wajib. Ia yang tampil sebelum video termuat, bila video gagal
      dimuat, dan bagi pengunjung yang meminta pengurangan gerak. Karena
      itu poster ikut menahan tata letak dan mencegah pergeseran.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   Blok media di dalam alur teks

   Rasio dikunci lewat aspect-ratio, bukan padding-hack, sehingga tinggi
   sudah terpesan sebelum berkas apa pun tiba.
   --------------------------------------------------------------------------- */
.media {
  margin: 0;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--ink-100);
  box-shadow: var(--shadow-md);
}

.media__frame {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.media__frame > img,
.media__frame > video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Video ditumpuk di atas poster. Selama video belum siap, atau bila ia
   memang tidak pernah diputar, poster di bawahnya yang terlihat. */
.media__frame > video {
  position: absolute;
  inset: 0;
  z-index: 1;
}

/* Keterangan bergaya editorial: rapat ke gambar, bukan kotak terpisah. */
.media__caption {
  padding: var(--space-xs) var(--space-sm);
  background: var(--surface);
  border-top: 1px solid var(--line);
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  color: var(--text-muted);
  letter-spacing: var(--track-snug);
}

/* Varian lebar: sedikit keluar dari kolom teks agar halaman punya irama,
   bukan satu lebar seragam dari atas ke bawah. */
@media (min-width: 900px) {
  .media--bleed {
    /* Luapannya dibatasi ruang yang benar-benar ada di kiri-kanan kolom, bukan
       nilai tetap. Dengan --space-xl mati (3,5rem = 56px per sisi) gambar ini
       menembus KEDUA tepi viewport di seluruh rentang 900–1230px: talang di
       lebar itu hanya 28–40px, jadi sisanya terpotong. Yang hilang bukan sekadar
       piksel — variannya bernama "sedikit keluar dari kolom teks", dan di rentang
       itu ia justru keluar dari layar.

       (100vw - 100%) / 2 adalah ruang di satu sisi kolom; `min()` mengambil mana
       yang lebih kecil antara efek yang diinginkan dan ruang yang tersedia,
       sehingga efeknya tetap penuh di layar lebar dan menyusut sendiri, bukan
       terpotong, saat layarnya tidak cukup. */
    --bleed: min(var(--space-xl), calc((100vw - 100%) / 2));
    width: calc(100% + 2 * var(--bleed));
    margin-inline: calc(-1 * var(--bleed));
  }
}

/* Varian potret pendek untuk sisipan di samping teks. */
.media--short .media__frame { aspect-ratio: 21 / 9; }

/* ---------------------------------------------------------------------------
   Media berdampingan dengan teks

   Sengaja tidak simetris: kolom teks lebih sempit dari kolom gambar pada
   varian --lead, dan sebaliknya pada varian biasa.
   --------------------------------------------------------------------------- */
.media-split {
  display: grid;
  gap: var(--space-lg);
  align-items: center;
}

@media (min-width: 900px) {
  .media-split { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); }
  .media-split--lead { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
  .media-split--reverse > .media { order: -1; }
}

/* ---------------------------------------------------------------------------
   Video latar hero

   Aturan .hero__media dan scrim-nya sudah dikalibrasi kontras di
   sections.css. Di sini video hanya menumpang aturan yang sama persis,
   termasuk object-position, sehingga tidak ada nilai alpha yang bergeser.
   --------------------------------------------------------------------------- */
.hero__media video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 65%;
  z-index: 1;
}

/* Poster hero berada di bawah video dengan aturan yang identik, sehingga
   pergantian dari poster ke video tidak menggeser komposisi sedikit pun. */
.hero__media img {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* Scrim harus tetap berada di atas keduanya. */
.hero__media::after { z-index: 2; }

/* ---------------------------------------------------------------------------
   Penghormatan terhadap prefers-reduced-motion

   Video disembunyikan sepenuhnya, bukan sekadar dihentikan, agar poster di
   bawahnya yang tampil. assets/js/media.js juga menahan pemutaran, tetapi
   aturan CSS ini tetap berlaku meski JS gagal dimuat.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .media__frame > video,
  .hero__media video {
    display: none;
  }
}
