@charset "utf-8";
/* =============================================================================
   Rakitwarna, situs perusahaan sendiri (paket 15)
   Sumber desain: stitch/15-compro-sendiri/ (DESIGN.md + PROMPTS-WEB/STATE)

   🟡 "RAKITWARNA" ADALAH NAMA KERJA SEMENTARA, bukan nama final. Owner belum
   memutuskan. Namanya sengaja hanya hidup di EMPAT tempat per halaman, jadi
   penggantian kelak cukup satu kali ganti-string:
     · gaya.css, HANYA di komentar ini (nol kemunculan di aturan CSS)
     · *.html, wordmark navbar (.wordmark), satu kalimat hero, wordmark
                   footer (.footer .wordmark), dan baris hak cipta "© 2026
                   Rakitwarna." di .footer-bawah
     · index.html tambahan: <title>, <meta name="description">, dan satu
       kalimat di section portofolio
   Cara mengganti: cari-ganti string "Rakitwarna" di situs/15-rakitwarna/*.html
   (CSS ini tidak perlu disentuh selain komentarnya).

   ⚫ SATU-SATUNYA SITUS BERTEMA GELAP di antara ke-15. Empat belas situs
   portofolio semuanya terang; kegelapan di sini disengaja supaya berdampingan
   mereka terbaca sebagai galeri dan bingkainya, bukan sebagai situs kelima
   belas yang mirip. TIDAK ADA satu pun arah warna yang diwarisi dari situs 14, seluruh rasio di bawah DIHITUNG ULANG dengan rumus WCAG (relative luminance)
   untuk latar GELAP.

   HASIL HITUNGAN, DAN PUTUSANNYA:
     tinta  #EEF3F8 di atas latar #0B0F14 = 17,22:1  LULUS (teks utama)
     tinta  di atas kartu #141A22         = 15,67:1  LULUS
     redup  #9BA9B8 di atas latar         =  8,02:1  LULUS (teks sekunder)
     redup  di atas kartu                 =  7,30:1  LULUS
     aksen  #4C8DFF di atas latar         =  6,00:1  LULUS lantai 3:1 DAN 4,5:1
     aksen  di atas kartu                 =  5,46:1  LULUS
     tinta  di atas aksen                 =  6,00:1  LULUS → teks di atas aksen
     putih  di atas aksen                 =  3,20:1  GAGAL → tidak pernah dipakai
     garis kendali #5A6B7E di atas latar  =  3,51:1  LULUS lantai 3:1
     garis kendali di atas kartu          =  3,20:1  LULUS lantai 3:1
     garis kartu #1E2732 di atas latar    =  1,27:1  DEKORATIF saja
   Angka DESIGN.md paket ini diperiksa satu per satu dan TERBUKTI BENAR sampai
   dua desimal (17,22 · 8,02 · 15,67 · 7,30 · 6,00 · 3,20 · 3,51 cocok semua), tapi ia tetap dihitung, bukan dipercaya.

   🔴 PAGAR YANG PALING SERING GAGAL DIAM-DIAM DI TEMA GELAP, dan berkas ini ada
   justru untuk menguncinya: garis fungsional (kolom isian, dropdown, cincin
   fokus, tombol bergaris) WAJIB --garis-kendali #5A6B7E, yaitu 3,51:1. Warna
   garis yang TERLIHAT pas di tema gelap, #263140, DIHITUNG SENDIRI dan hasilnya
   1,46:1, persis seperti yang ditulis DESIGN.md. Ia lenyap bagi mata dengan
   sensitivitas kontras rendah, tanpa satu pun galat dan tanpa perubahan tata
   letak. #1E2732 (1,27:1) lebih parah lagi dan karena itu DILARANG menyentuh
   kendali apa pun; ia hanya boleh jadi tepi dekoratif kartu yang sudah
   terpisahkan oleh warna permukaannya sendiri.

   PUTUSAN AKSEN, KEBALIKAN dari situs 14, dan itu hasil hitungan bukan selera:
   biru #4C8DFF ada di 6,00:1 terhadap latar, jauh DI ATAS lantai 3:1 sekaligus
   di atas 4,5:1. Jadi di paket ini aksen BOLEH jadi warna teks, garis, ikon
   fungsional, garis bawah item aktif, DAN cincin fokus. Yang DILARANG justru
   kebalikan situs 14: membawa teks PUTIH di atas isian aksen (3,20:1, GAGAL AA).
   Teks di atas isian aksen selalu --latar #0B0F14.

   TIGA AKIBAT LAIN YANG DITEGAKKAN DI BERKAS INI:
     · Isian aksen TIDAK perlu garis penolong. Di situs 14 tiap isian emas diberi
       garis tinta karena tepinya cuma 2,24:1 terhadap latar; di sini tepinya
       6,00:1 dan garis tambahan justru mengotori bentuknya.
     · Keadaan hover/tekan MENERANGKAN aksen (#6BA0FF, 7,41:1), kebalikan dari
       situs 14 yang menggelapkannya. Menggelapkan di tema gelap berarti isian
       tombol mendekati latarnya sendiri.
     · Footer TIDAK bisa memakai --tinta sebagai alas seperti situs 14, di sini
       --tinta nyaris putih. Footer memakai #0F141B, sedikit di bawah latar,
       dengan tinta 16,56:1 dan tautan #A8B5C2 8,85:1 di atasnya.

   ⛔ RAMBU ISI (DESIGN.md + ATURAN-KONTEN.md), berlaku di CSS maupun HTML:
   Situs ini situs perusahaan SUNGGUHAN, jadi TIDAK ADA pita "desain contoh" di
   atas navbar, dan justru karena itu TIAP KARTU PORTOFOLIO WAJIB membawa label
   kecil "desain contoh" (.cip-contoh), dan section portofolio membuka dengan
   kalimat yang menyatakannya terang-terangan. DILARANG menulis "klien kami",
   "dipercaya oleh", atau memasang ke-14 nama perusahaan itu sebagai logo klien:
   mereka tidak ada, dan menyebutnya klien adalah kebohongan yang bisa diperiksa
   dalam satu pencarian. Tidak ada nomor izin, sertifikat, atau registrasi apa
   pun. Tidak ada klaim "company profile syarat tender pemerintah", sudah
   diperiksa ke Standar Dokumen Pemilihan LKPP: nol kemunculan.

   HURUF: Plus Jakarta Sans 700 (judul, angka, harga) + Inter 400 (isi), sesuai
   DESIGN.md. Keduanya diperiksa dengan fontTools pada berkas woff2 di
   aset/huruf/, catatannya lengkap di _font-face.css. Yang paling penting:
   sumbu fvar Plus Jakarta Sans hanya 200–800 (BUKAN 100–900), dan `tnum`
   sungguhan ada di keduanya, jadi `tabular-nums` di halaman penuh harga ini
   benar-benar bekerja.
   ========================================================================== */

@import url("aset/huruf/_font-face.css");

/* -----------------------------------------------------------------------------
   1. TOKEN, tiap warna punya PERAN dan RASIO TERHITUNG di sebelahnya.
   -------------------------------------------------------------------------- */
:root {
  /* Permukaan, TEMA GELAP */
  --latar:        #0B0F14;   /* alas halaman */
  --kertas:       #141A22;   /* alas kartu di atas --latar; tinta 15,67:1 · redup 7,30:1 */
  --sentuh:       #1C2530;   /* hover/tekan; tinta di atasnya 13,87:1 */

  /* Teks */
  --tinta:        #EEF3F8;   /* 17,22:1 di atas --latar, teks utama, ukuran apa pun */
  --redup:        #9BA9B8;   /* 8,02:1 di atas --latar dan 7,30:1 di atas --kertas, LULUS AA */

  /* Aksen, BOLEH jadi teks, garis, ikon, dan cincin fokus */
  --aksen:        #4C8DFF;   /* 6,00:1 di atas latar (5,46:1 di atas kartu) → lulus lantai
                                3:1 untuk garis/ikon DAN 4,5:1 untuk teks. Karena itu di
                                paket ini aksen boleh jadi warna teks, garis bawah item
                                aktif, ikon fungsional, dan cincin fokus, kebalikan dari
                                situs 14, dan itu hasil hitungan bukan kebiasaan.
                                Teks DI ATAS isian aksen wajib --latar (6,00:1); PUTIH di
                                atasnya cuma 3,20:1 dan GAGAL AA. Tepi isian aksen sudah
                                6,00:1 terhadap latar, jadi ia TIDAK diberi garis penolong
                                seperti di situs 14. */
  --aksen-tekan:  #6BA0FF;   /* hover/tekan LEBIH TERANG: 7,41:1 terhadap latar, dan --latar
                                di atasnya juga 7,41:1. Menggelapkan aksen di tema gelap
                                justru mendekatkan tombol ke latarnya sendiri. */
  --aksen-alas:   #16233A;   /* alas lembut; tinta di atasnya 14,08:1, redup 6,56:1.
                                ⚠️ --garis-kendali di atasnya cuma 2,87:1, jadi kendali
                                bergaris TIDAK PERNAH diletakkan di atas alas ini. */
  --nonaktif:     #1B2531;   /* alas kendali mati; redup di atasnya 6,46:1 */

  /* Garis */
  --garis:        #1E2732;   /* 1,27:1, DEKORATIF saja (pemisah, tepi kartu yang sudah
                                terpisah oleh warna permukaannya). DILARANG untuk kendali. */
  --garis-kendali:#5A6B7E;   /* 3,51:1 di atas latar, 3,20:1 di atas kartu, border input,
                                dropdown, checkbox, tombol bergaris, cincin fokus.
                                🔴 JANGAN diganti #263140 (1,46:1) atau #1E2732 (1,27:1)
                                betapapun "pas"-nya kelihatan: itu kegagalan senyap paling
                                umum di antarmuka gelap, dan DESIGN.md menulisnya eksplisit. */

  /* Semantik, dihitung terhadap --latar dan terhadap alasnya masing-masing */
  --sukses:       #5CD6A0;   /* 10,60:1 di atas latar · 8,97:1 di atas --sukses-alas */
  --galat:        #FF8A80;   /*  8,42:1 di atas latar · 7,60:1 di atas --galat-alas */
  --peringatan:   #F5C26B;   /* 11,73:1 di atas latar · 9,67:1 di atas --peringatan-alas */
  --sukses-alas:  #10241C;   /* tinta di atasnya 14,57:1, redup 6,79:1 */
  --galat-alas:   #2A1416;   /* tinta di atasnya 15,55:1, redup 7,24:1 */
  --peringatan-alas:#2A2113; /* tinta di atasnya 14,19:1, redup 6,61:1 */

  /* Huruf. DUA keluarga, sesuai DESIGN.md: Plus Jakarta Sans 700 untuk judul,
     angka, dan harga; Inter 400 untuk isi.
     ⚠️ DIPERIKSA dengan fontTools pada woff2 di aset/huruf/, bukan ditebak dari
     unicode-range yang dideklarasikan Google:
       · U+2192 (→) dan U+2190 (←) TIDAK ADA di KEDUA huruf, padahal keduanya
         mendeklarasikan U+2000-206F. Ini huruf keenam dan ketujuh berturut-turut
         yang begitu, jadi panah di halaman ini SELALU ikon SVG (#i-panah),
         tidak pernah aksara.
       · U+00B7 (·) · U+2013 (–) · U+2014 (-) · U+2019 (’) · U+2026 (…) ·
         U+00D7 (×) · U+00B0 (°) · U+00A9 (©) · U+0025 (%) SEMUANYA ADA.
       · SUMBU fvar Plus Jakarta Sans hanya wght 200–800, BUKAN 100–900 seperti
         Inter. Menyalin `font-weight: 100 900` ke @font-face-nya berarti meminta
         bobot di luar sumbu, dan peramban menjepitnya DIAM-DIAM. Lihat
         _font-face.css: bobotnya ditulis 200 800 untuk yang satu dan 100 900
         untuk yang lain.
       · `tnum` ADA di keduanya, dan ia benar-benar mengubah lebar: lebar angka
         bawaan Inter 833–1323 per 2048 upem menjadi 1328 rata, dan Plus Jakarta
         Sans 371–732 per 1000 upem menjadi 600 rata. Jadi `tabular-nums` di
         halaman yang penuh harga ini BEKERJA, bukan dideklarasikan begitu saja.
     Rantai cadangan diisi huruf sistem yang pasti punya glif yang kurang. */
  --f-judul: "Plus Jakarta Sans", ui-sans-serif, "Segoe UI", system-ui, sans-serif;
  --f-isi:   "Inter", ui-sans-serif, "Segoe UI", system-ui, sans-serif;

  /* LANTAI UKURAN TEKS, jangan turun di bawah ini di mana pun. */
  --t-isi:   1rem;      /* 16px, teks isi */
  --t-kecil: 0.875rem;  /* 14px, sekunder */
  --t-label: 0.75rem;   /* 12px, label huruf besar, BATAS BAWAH */

  /* Ritme */
  --r1: .25rem; --r2: .5rem; --r3: .75rem; --r4: 1rem;
  --r5: 1.5rem; --r6: 2rem; --r7: 3rem; --r8: 4rem; --r9: 6rem;

  --radius: 8px;                    /* DESIGN.md: kartu 8px, tombol dan kolom 6px */
  --radius-kecil: 6px;
  --lebar-isi: 1240px;
  --tepi: 1.25rem;

  --bar-atas: 0px;
  --bar-bawah: calc(56px + env(safe-area-inset-bottom, 0px));

}

/* -----------------------------------------------------------------------------
   2. DASAR
   -------------------------------------------------------------------------- */
/* WAJIB, dan sempat hilang saat kepala berkas ini ditulis ulang: tanpa baris ini
   padding-inline .bungkus DITAMBAHKAN ke lebar 100%, jadi tiap halaman meluber
   tepat 40px (2 × --tepi) di layar sempit dan 40px di navbar pada layar lebar.
   Ketiga audit teks tetap hijau saat itu, hanya pengukur responsif yang melihat. */
*, *::before, *::after { box-sizing: border-box; }

/* Atribut `hidden` KALAH oleh `display` mana pun yang ditulis di CSS. Gejalanya
   mahal dan hanya terlihat setelah dirender: pesan galat formulir tampil sejak
   halaman dibuka karena .pesan menyetel display:flex. Satu aturan ini menutup
   seluruh kelasnya. */
[hidden] { display: none !important; }

html {
  /* Jangkar berhenti tepat di bawah bar, dan ini juga menyelamatkan elemen yang
     menerima fokus keyboard (teknik W3C C43 untuk WCAG 2.2 SC 2.4.11). */
  scroll-padding-top: calc(var(--bar-atas) + var(--r4));
  scroll-padding-bottom: calc(var(--bar-bawah) + var(--r4));
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--latar);
  color: var(--tinta);
  font-family: var(--f-isi);
  font-size: var(--t-isi);
  line-height: 1.6;
  /* Ruang untuk bar tab bawah di mobile supaya isi terakhir tidak tertutup. */
  padding-bottom: var(--bar-bawah);
}

h1, h2, h3, h4 { font-family: var(--f-judul); font-weight: 700; line-height: 1.2; margin: 0; }
h1 { font-size: clamp(2.125rem, 5vw, 3.375rem); letter-spacing: -0.01em; }
h2 { font-size: clamp(1.5rem, 3.2vw, 2.25rem); letter-spacing: -0.01em; }
h3 { font-size: clamp(1.125rem, 1.9vw, 1.375rem); }
p  { margin: 0; }
img { max-width: 100%; height: auto; display: block; }
ul, ol { margin: 0; padding: 0; list-style: none; }
a { color: inherit; }

/* Harga dan angka: Plus Jakarta Sans 700, sesuai DESIGN.md ("Numbers and prices:
   Plus Jakarta Sans, 700, tabular figures"). BOBOTNYA 700, bukan 800 warisan situs
   14, sumbu fvar huruf ini berhenti di 800 dan brief memang menulis 700.
   `tabular-nums` di sini BENAR-BENAR bekerja, dan itu diukur bukan diasumsikan:
   lebar angka bawaan Plus Jakarta Sans 371–732 per 1000 upem, dan seluruh varian
   tabularnya 600 rata; Inter 833–1323 per 2048 upem menjadi 1328 rata. Halaman ini
   penuh kolom rupiah, jadi ini bukan detail. */
.angka { font-family: var(--f-judul); font-weight: 700; font-variant-numeric: tabular-nums; }
/* Angka yang DIBANDINGKAN LAWAN BARIS LAIN, huruf yang sama, bobot lebih ringan
   supaya tabel tidak berubah jadi dinding tebal. */
.angka-tabel { font-family: var(--f-isi); font-weight: 600; font-variant-numeric: tabular-nums; }

/* CINCIN FOKUS, 2px AKSEN dengan offset 2px, persis seperti yang diminta S1, S2,
   dan S8. Di situs 14 permintaan yang sama TIDAK bisa dituruti karena emasnya cuma
   2,24:1; di sini biru #4C8DFF ada di 6,00:1 terhadap latar dan 5,46:1 terhadap
   kartu, jadi cincin fokus beraksen benar-benar terlihat. Ini contoh kenapa putusan
   warna paket sebelumnya tidak boleh diwarisi tanpa dihitung ulang. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--aksen);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Lewati ke konten, wajib ada, dan wajib terlihat saat difokus. Isian AKSEN
   dengan teks --latar (6,00:1); putih di atasnya 3,20:1 dan GAGAL. */
.lewati {
  position: absolute; left: var(--tepi); top: -100px; z-index: 100;
  background: var(--aksen); color: var(--latar); padding: var(--r3) var(--r4);
  border-radius: var(--radius); font-weight: 600; text-decoration: none;
}
.lewati:focus-visible { top: var(--r3); }

/* -----------------------------------------------------------------------------
   3. TATA LETAK
   -------------------------------------------------------------------------- */
.bungkus { width: 100%; max-width: var(--lebar-isi); margin-inline: auto; padding-inline: var(--tepi); }
.bagian { padding-block: var(--r7); }
.bagian + .bagian { border-top: 1px solid var(--garis); }
@media (min-width: 768px) { .bagian { padding-block: var(--r8); } }

.kepala-bagian { margin-bottom: var(--r5); max-width: 62ch; }
.kepala-bagian p { color: var(--redup); margin-top: var(--r2); }

.kisi { display: grid; gap: var(--r4); }
@media (min-width: 640px)  { .kisi-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 900px)  { .kisi-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
                             .kisi-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 640px) and (max-width: 899px) { .kisi-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Tiap anak kisi WAJIB boleh menyusut, kalau tidak isi yang lebar mendorong
   lebar halaman dan yang dilaporkan meluber justru elemen lain. */
.kisi > * { min-width: 0; }

/* -----------------------------------------------------------------------------
   4. TIDAK ADA PITA "DESAIN CONTOH" DI SITUS INI, dan itu disengaja.
   Ke-14 situs portofolio wajib memakainya karena perusahaannya fiktif. Situs ini
   perusahaan SUNGGUHAN, jadi pita itu justru akan berbohong ke arah sebaliknya.
   Kejujurannya dipindah ke tempat yang benar: label kecil "desain contoh" di TIAP
   kartu portofolio (.cip-contoh, bagian 42) dan satu kalimat pembuka di section
   portofolio yang menyatakannya terang-terangan.
   Kelas .pita sengaja TIDAK diturunkan ke berkas ini supaya tidak ada yang
   memakainya karena kebiasaan.
   -------------------------------------------------------------------------- */

/* -----------------------------------------------------------------------------
   5. NAVBAR (desktop), di mobile digantikan bar tab bawah
   -------------------------------------------------------------------------- */
/* Navbar melekat di puncak. S8 meminta dua keadaan: 80px transparan di puncak
   halaman, 60px beralas #0B0F14 dengan garis bawah 1px #1E2732 sesudah di-scroll.
   Keduanya dilayani atribut data-scroll yang ditulis situs.js. */
.navbar { background: var(--latar); border-bottom: 1px solid transparent;
          position: sticky; top: 0; z-index: 30; transition: border-color .15s ease; }
.navbar[data-scroll="ya"] { border-bottom-color: var(--garis); }
.navbar-isi { display: flex; align-items: center; gap: var(--r4); min-height: 64px; }
.wordmark {
  font-family: var(--f-judul); font-weight: 600; letter-spacing: .06em;
  font-size: 0.9375rem; text-decoration: none; white-space: nowrap;
}
.nav-tautan { display: none; gap: var(--r5); margin-inline: auto; }
.nav-tautan a { text-decoration: none; color: var(--redup); font-size: var(--t-kecil); }
.nav-tautan a:hover { color: var(--tinta); }
/* Item aktif TIDAK dibedakan warna saja, ada garis bawah tebal juga.
   S8 meminta garis bawah 2px beraksen, dan di paket ini permintaan itu BISA
   dituruti apa adanya: #4C8DFF ada di 6,00:1 terhadap latar, dua kali lipat
   lantai 3:1 untuk penanda non-teks. Di situs 14 permintaan yang sama terpaksa
   ditolak (emas 2,24:1). Bedanya hitungan, bukan selera. */
.nav-tautan a[aria-current="page"] {
  color: var(--tinta); font-weight: 700;
  box-shadow: inset 0 -2px 0 0 var(--aksen);
}
@media (min-width: 900px) { .nav-tautan { display: flex; } }
.navbar .tombol { margin-left: auto; }
@media (min-width: 900px) { .navbar .tombol { margin-left: 0; } }

/* -----------------------------------------------------------------------------
   6. TOMBOL, target sentuh minimal 48px, tombol utama 52px di mobile
   -------------------------------------------------------------------------- */
.tombol {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--r2);
  min-height: 48px; padding: var(--r3) var(--r5);
  /* 16px bobot 600. Alasannya target sentuh dan ritme: label tombol yang mengecil
     membuat tinggi 48px terlihat kosong. */
  font-family: var(--f-isi); font-size: var(--t-isi); font-weight: 600;
  border-radius: var(--radius-kecil); border: 1px solid transparent;   /* DESIGN.md: tombol 6px */
  text-decoration: none; cursor: pointer; background: none; color: var(--tinta);
  transition: background-color .15s ease, border-color .15s ease;
}
/* Tombol beraksen TANPA garis penolong, kebalikan dari situs 14: di sana isian emas
   cuma 2,24:1 terhadap latar sehingga tepinya perlu ditolong garis; di sini isian
   #4C8DFF ada di 6,00:1 dan garis tambahan justru mengotori bentuknya.
   Labelnya --latar (6,00:1). PUTIH di atasnya 3,20:1 dan GAGAL AA, inilah satu
   kesalahan yang paling gampang masuk ke tombol biru. */
.tombol-utama { background: var(--aksen); color: var(--latar); }
.tombol-utama:hover { background: var(--aksen-tekan); }            /* 7,41:1, lebih TERANG */
.tombol-utama:active { background: var(--aksen-tekan); }
/* S2 "DITEKAN": isian sedikit lebih gelap dari keadaan aktif, tapi TIDAK lebih
   gelap dari aksen itu sendiri, 4,69:1 masih di atas AA untuk label --latar. */
.tombol-utama[data-keadaan="ditekan"] { background: #3D7AE6; }     /* --latar di atasnya 4,69:1 */
.tombol-kedua { border-color: var(--garis-kendali); color: var(--tinta); }  /* garis 3,51:1 */
.tombol-kedua:hover { background: var(--sentuh); }
.tombol-blok { width: 100%; }
.tombol[disabled], .tombol[aria-disabled="true"] {
  background: var(--nonaktif); color: var(--redup); border-color: transparent;  /* 6,46:1 */
  cursor: not-allowed;
}
.tombol-alasan { font-size: var(--t-kecil); color: var(--redup); margin-top: var(--r2); }

/* Keadaan memuat: tombol punya LABELNYA SENDIRI, bukan cuma spinner. */
.tombol[data-memuat="ya"] { pointer-events: none; }
.pemintal {
  width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  animation: putar .7s linear infinite; flex: none;
}
@keyframes putar { to { transform: rotate(360deg); } }

/* -----------------------------------------------------------------------------
   7. IKON, SVG sebaris, BUKAN emoji dan bukan font ikon.
   Brief menyebut Material Symbols; yang dipakai di sini SVG sebaris dengan bentuk
   yang sama maknanya. Alasannya bukan selera: font ikon berbasis ligatur
   menampilkan nama glyph sebagai teks mentah sebelum fontnya termuat, dan itu
   berarti kata "request_quote" sempat terbaca di layar pembeli.
   -------------------------------------------------------------------------- */
.ikon { width: 20px; height: 20px; flex: none; stroke: currentColor;
        fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.ikon-besar { width: 28px; height: 28px; }
.ikon-redup { color: var(--redup); }
/* .ikon-aksen ADA di paket ini, dan itu putusan terhitung: biru 6,00:1 di atas
   latar dan 5,46:1 di atas kartu, dua-duanya jauh di atas lantai 3:1 untuk ikon
   fungsional. Di situs 14 kelas ini sengaja tidak ada karena emasnya 2,24:1. */
.ikon-aksen { color: var(--aksen); }
.ikon-sukses { color: var(--sukses); }        /* 10,60:1 */
.ikon-peringatan { color: var(--peringatan); } /* 11,73:1, "muted amber" versi tema gelap */
.ikon-galat { color: var(--galat); }          /* 8,42:1 */

/* -----------------------------------------------------------------------------
   8. KARTU, border 1px, TANPA bayangan (DESIGN.md)
   -------------------------------------------------------------------------- */
.kartu {
  background: var(--kertas); border: 1px solid var(--garis);
  border-radius: var(--radius); padding: var(--r4);
}
.kartu h3 { margin-bottom: var(--r2); }
/* 🔴 DIKURUNG, dan kurungnya bukan kehati-hatian melainkan tambalan cacat yang
   BENAR-BENAR TERJADI di berkas ini dan lolos dari ketiga audit.
   `.kartu p` (0,1,1) mengalahkan kelas spesifik (0,1,0) yang kebetulan duduk di
   sebuah <p> di dalam kartu. Diukur dari peramban dengan getComputedStyle,
   bukan dibaca dari kode:
     · .harga-angka, HARGA, angka terpenting di seluruh halaman ini, keluar 14px #9BA9B8 alih-alih 36px #EEF3F8. Halaman yang seluruh
       jualannya "harga kami tulis di sini" menulis harganya dengan huruf
       terkecil dan warna paling redup di halaman.
     · .potret-inisial, 28px jatuh ke 14px, jadi inisial tim menyusut jadi
       seukuran teks catatan kaki.
   Ini kejadian KELIMA dari kelas cacat yang sama di project ini, dan seperti
   empat sebelumnya ia hijau di periksa.py, hijau di periksa-verbatim.py, dan
   hijau di ukur-responsif.mjs, karena audit membaca teks dan kotak, bukan
   warna dan ukuran terhitung. */
.kartu p:not(.angka):not(.potret-inisial):not(.galat-kode) { color: var(--redup); font-size: var(--t-kecil); }

/* Cip beraksen: 14px bobot 600, teks --latar di atas biru 6,00:1. TANPA garis, tepi isiannya sendiri sudah 6,00:1 terhadap latar.
   ⚠️ .cip TIDAK BOLEH kecolongan aturan turunan. Di situs 13 sebuah aturan
   `.pita-statistik span:last-child` (0,2,1) mencuri `.cip` (0,1,0) dan menjatuhkan
   cip di atas isian aksen ke 1,94:1. Karena itu tiap aturan turunan di berkas ini
   yang menyetel color/font-size pada elemen generik dikurung `:not(.cip)`. */
.cip {
  display: inline-block; background: var(--aksen); color: var(--latar);  /* 6,00:1 */
  font-size: var(--t-kecil); font-weight: 600; letter-spacing: .02em;
  padding: 2px var(--r3); border-radius: 999px;
}
.cip-netral { background: var(--nonaktif); color: var(--tinta); }        /* 13,88:1 */
/* Status TIDAK PERNAH dibawa warna saja, tiap cip memasangkan ikon, kata, dan
   warna sekaligus. Bordernya TINTA, bukan aksen: 2,24:1 tidak sampai ke lantai
   3:1 untuk garis. */
.cip-garis {
  /* inline-flex, BUKAN inline-block warisan .cip: cip bergaris hampir selalu
     membawa ikon, dan sebagai inline-block ikonnya duduk di garis dasar teks lalu
     terlihat seperti glyph yang rusak. */
  display: inline-flex; align-items: center; gap: var(--r2);
  background: var(--kertas); color: var(--tinta);
  border: 1px solid var(--garis-kendali); text-transform: none; letter-spacing: 0;  /* 3,20:1 */
  font-size: var(--t-kecil); padding: var(--r1) var(--r3);
}

.tautan-panah {
  display: inline-flex; align-items: center; gap: var(--r1);
  font-size: var(--t-kecil); font-weight: 600; text-decoration: none;
  /* AKSEN sebagai warna teks, dan ini sah di sini: 6,00:1 di atas latar, 5,46:1 di
     atas kartu. Di situs 14 baris yang sama terpaksa bertinta karena emasnya
     2,24:1, tempat menyalin paling berbahaya kalau tidak dihitung ulang. */
  color: var(--aksen); text-underline-offset: 3px;
}
.tautan-panah:hover { text-decoration: underline; }

/* -----------------------------------------------------------------------------
   9. HERO
   -------------------------------------------------------------------------- */
.hero { display: grid; gap: var(--r5); align-items: center; }
@media (min-width: 900px) { .hero { grid-template-columns: 1.05fr .95fr; gap: var(--r7); } }
.hero-mata { font-size: var(--t-kecil); font-weight: 600; color: var(--redup); letter-spacing: .06em; text-transform: uppercase; }
.hero h1 { margin-block: var(--r3); }
.hero-sub { color: var(--redup); font-size: 1.0625rem; max-width: 56ch; }
.hero-aksi { display: flex; flex-wrap: wrap; gap: var(--r3); margin-top: var(--r5); }
.hero-aksi .tombol { min-height: 52px; }      /* aksi utama di mobile 52px */
.hero-statistik { display: flex; flex-wrap: wrap; gap: var(--r5); margin-top: var(--r5);
                  padding-top: var(--r4); border-top: 1px solid var(--garis); }
.hero-statistik div { min-width: 0; }
.hero-statistik .angka { font-size: 1.25rem; display: block; }
/* ⚠️ DIKURUNG :not(.cip):not(.angka). Aturan berbentuk `.induk span:last-child`
   (0,2,1) mencuri kelas spesifik (0,1,0) yang kebetulan duduk di elemen itu, dan
   itu kelas cacat paling produktif di project ini, sudah empat kejadian di tiga
   situs, dan keempatnya LOLOS dari ketiga audit karena audit membaca teks dan
   kotak, bukan warna dan ukuran terhitung. */
.hero-statistik span:last-child:not(.cip):not(.angka) { font-size: var(--t-kecil); color: var(--redup); }
.hero-foto { border-radius: var(--radius); border: 1px solid var(--garis); overflow: hidden;
              position: relative; }   /* blok penampung untuk keturunan absolut */
.hero-foto img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

/* -----------------------------------------------------------------------------
   10. PITA STATISTIK BERAKSEN, SELURUH teks di atasnya wajib --latar #0B0F14.
   Terhitung sendiri: --latar di atas biru #4C8DFF 6,00:1 LULUS, PUTIH di atasnya
   3,20:1 GAGAL. Arah larangannya persis KEBALIKAN situs 14, tempat justru teks
   gelap yang aman dan putih yang gagal, kebetulan sama arahnya, tapi angkanya
   berbeda dan keduanya dihitung terpisah.
   -------------------------------------------------------------------------- */
.pita-statistik { background: var(--aksen); color: var(--latar); padding-block: var(--r6); }
.pita-statistik .kisi { gap: var(--r5); grid-template-columns: repeat(2, minmax(0,1fr)); }
@media (min-width: 900px) { .pita-statistik .kisi { grid-template-columns: repeat(5, minmax(0,1fr)); } }
.pita-statistik .angka { font-size: clamp(1.375rem, 2.3vw, 1.75rem); display: block; }
/* Dikurung :not(.cip):not(.angka) karena alasan yang sama dengan .hero-statistik:
   inilah selektor persis yang di situs 13 mencuri .cip dan menjatuhkannya ke
   1,94:1. Kurungnya ditulis SEKARANG, bukan ditemukan saat audit, ketiga audit
   buta terhadap kelas cacat ini. */
.pita-statistik span:last-child:not(.cip):not(.angka) { font-size: var(--t-kecil); font-weight: 500; }
/* Cincin fokus di atas pita beraksen: aksen di atas aksen tidak terlihat, jadi di
   sini SAJA cincinnya --latar (6,00:1 terhadap isian pita). */
.pita-statistik :focus-visible { outline-color: var(--latar); }

/* Pita kalimat beraksen, sama aturannya, teks --latar (6,00:1). */
.pita-aksen {
  background: var(--aksen); color: var(--latar); border-radius: var(--radius);
  padding: var(--r5); font-size: 1.0625rem;
}
.pita-aksen :focus-visible { outline-color: var(--latar); }

/* -----------------------------------------------------------------------------
   11. BARIS DAFTAR NATIVE, padanan mobile untuk tabel dan dropdown.
   Tinggi minimal 56px. Dipakai juga di desktop karena polanya memang terbaca.
   -------------------------------------------------------------------------- */
.daftar { border: 1px solid var(--garis); border-radius: var(--radius); background: var(--kertas); }
.baris {
  display: flex; align-items: center; gap: var(--r3);
  min-height: 56px; padding: var(--r3) var(--r4);
  border-bottom: 1px solid var(--garis);
}
.baris:last-child { border-bottom: 0; }
.baris-isi { min-width: 0; flex: 1; }
/* Keduanya WAJIB blok. Sebagai span inline, judul dan keterangannya menyambung
   jadi satu paragraf dan barisnya berhenti terbaca sebagai baris daftar native, terlihat jelas di 390px, tidak terlihat sama sekali dari kode. */
.baris-label { display: block; font-weight: 600; font-size: var(--t-kecil); }
.baris-nilai { display: block; font-size: var(--t-kecil); color: var(--redup); }
/* Baris dua kolom (label kiri, nilai kanan) tetap sebaris: di situ keterangannya
   pendek dan memang berpasangan, bukan judul-dan-penjelasan. */
.baris > .baris-nilai:first-child { display: inline; }
/* TANPA nowrap. Nilai panjang seperti "Monday to Friday 08.00 to 17.00, Saturday
   08.00 to 13.00, GMT+7" tidak bisa membungkus dan mendorong lebar halaman:
   terukur meluber 54px di 320px pada situs 02, dan yang dilaporkan meluber justru
   <main>, bukan span penyebabnya. */
.baris-kanan { margin-left: auto; font-weight: 600; font-size: var(--t-kecil);
               text-align: right; min-width: 0; overflow-wrap: anywhere; }
.baris-kanan.angka { font-weight: 600; }
a.baris { text-decoration: none; }
a.baris:hover { background: var(--sentuh); }

/* -----------------------------------------------------------------------------
   12. TABEL, GARIS MENDATAR SAJA, tinggi baris 48px (DESIGN.md).
   Di bawah 768px tabel lebar tetap bisa digulir mendatar di dalam kotaknya
   sendiri; halamannya TIDAK ikut bergeser.
   -------------------------------------------------------------------------- */
.tabel-bungkus { overflow-x: auto; border: 1px solid var(--garis); border-radius: var(--radius);
                 background: var(--kertas);
                 /* WAJIB. Lihat komentar panjang di atas: tanpa ini .hanya-layar-baca
                    di dalam tabel lolos dari pangkasan overflow dan menarik lebar
                    dokumen sampai 263px melewati layar 390px. */
                 position: relative; }
table { border-collapse: collapse; width: 100%; font-size: var(--t-kecil); }
th, td { text-align: left; padding: var(--r3) var(--r4); border-bottom: 1px solid var(--garis);
         height: 48px; }
th { font-weight: 600; background: var(--sentuh); white-space: nowrap; }  /* tinta 13,87:1 */
/* Angka lajur dua dan seterusnya dibandingkan lawan lajur → tabular. */
td:not(:first-child) { font-variant-numeric: tabular-nums; }
tr:last-child td { border-bottom: 0; }
caption { caption-side: top; text-align: left; padding: var(--r3) var(--r4);
          font-size: var(--t-kecil); color: var(--redup); }

/* -----------------------------------------------------------------------------
   13. CAROUSEL GESER, kartu berikutnya mengintip, ada titik indikator
   -------------------------------------------------------------------------- */
.carousel {
  display: grid; grid-auto-flow: column; grid-auto-columns: min(78%, 320px);
  gap: var(--r4); overflow-x: auto; scroll-snap-type: x mandatory;
  padding-bottom: var(--r3); scrollbar-width: thin;
  /* Geser mendatar ditangkap carousel, gulir tegak halaman tetap jalan. */
  touch-action: pan-y;
}
.carousel > * { scroll-snap-align: start; }
@media (min-width: 900px) {
  .carousel { grid-auto-flow: row; grid-template-columns: repeat(3, minmax(0,1fr));
              overflow: visible; scroll-snap-type: none; }
}
.titik { display: flex; gap: var(--r2); justify-content: center; margin-top: var(--r3); }
.titik span { width: 6px; height: 6px; border-radius: 50%; background: var(--garis-kendali); opacity: .45; }
.titik span[data-aktif="ya"] { background: var(--aksen); }   /* 6,00:1, penanda, bukan hiasan */
.titik span[data-aktif="ya"] { opacity: 1; width: 18px; border-radius: 3px; }
@media (min-width: 900px) { .titik { display: none; } }

/* -----------------------------------------------------------------------------
   14. TIMELINE, tegak di mobile, mendatar di layar lebar.
   ⚠️ LIMA langkah di paket ini (W8), bukan enam seperti situs 14 dan bukan tujuh
   seperti situs 08. Jumlah kolom timeline SELALU ikut diperiksa saat menyalin:
   kisi enam yang menampung lima meninggalkan satu kolom menganga di ujung kanan,
   dan itu hanya terlihat sesudah dirender.
   -------------------------------------------------------------------------- */
.timeline { position: relative; padding-left: 44px; }
.timeline::before {
  content: ""; position: absolute; left: 15px; top: 12px; bottom: 12px;
  width: 2px; background: var(--garis-kendali);   /* 3,51:1, garis ini membawa urutan */
}
.langkah { position: relative; padding-bottom: var(--r5); }
.langkah:last-child { padding-bottom: 0; }
.langkah-nomor {
  position: absolute; left: -44px; top: 0; width: 32px; height: 32px;
  display: grid; place-items: center; border-radius: 50%;
  background: var(--aksen); color: var(--latar);         /* 6,00:1, W8 minta angka ink di
                                                            atas lingkaran beraksen */
  font-family: var(--f-judul); font-weight: 700; font-size: var(--t-kecil);
}
.langkah h3 { font-size: 1.0625rem; }
.langkah p { color: var(--redup); font-size: var(--t-kecil); margin-top: var(--r1); }
/* LIMA kolom hanya dinyalakan di ≥1100px; di bawah itu timeline tetap TEGAK,
   karena keterangan tiap langkah di sini satu kalimat penuh dan tidak pernah muat
   di kolom 200px. Garis atas per langkah memakai --garis-kendali (3,51:1), bukan
   --garis (1,27:1): ia penanda urutan, bukan hiasan. */
@media (min-width: 1100px) {
  .timeline-5 { display: grid; grid-template-columns: repeat(5, minmax(0,1fr));
                gap: var(--r5) var(--r4); padding-left: 0; }
  .timeline-5::before { display: none; }      /* diganti border per langkah */
  .timeline-5 > .langkah { padding: calc(var(--r5) + 16px) 0 0;
                           border-top: 2px solid var(--garis-kendali); min-width: 0; }
  .timeline-5 > .langkah-nomor, .timeline-5 .langkah-nomor { left: 0; top: -16px; }
  .timeline-5 .langkah h3 { font-size: 1rem; }
}

/* -----------------------------------------------------------------------------
   15. AKORDEON FAQ, <details> asli, jadi tetap bisa dibuka tanpa JavaScript
   -------------------------------------------------------------------------- */
.faq { border: 1px solid var(--garis); border-radius: var(--radius); background: var(--kertas); }
.faq details { border-bottom: 1px solid var(--garis); }
.faq details:last-child { border-bottom: 0; }
.faq summary {
  display: flex; align-items: center; gap: var(--r3); cursor: pointer;
  min-height: 56px; padding: var(--r3) var(--r4);
  font-weight: 600; font-size: var(--t-kecil); list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary .ikon { margin-left: auto; transition: transform .2s ease; color: var(--aksen); }
.faq details[open] summary .ikon { transform: rotate(180deg); }
.faq .jawab { padding: 0 var(--r4) var(--r4); color: var(--redup); font-size: var(--t-kecil); }

/* -----------------------------------------------------------------------------
   16. FORMULIR, 🔴 BAGIAN PALING PENTING DI SELURUH BERKAS INI.
   Border kolom WAJIB --garis-kendali #5A6B7E (3,51:1 di atas latar, 3,20:1 di atas
   kartu). Warna garis yang TERLIHAT pas di tema gelap, #263140, DIHITUNG SENDIRI
   dan hasilnya 1,46:1, persis angka yang ditulis DESIGN.md, dan ia lenyap bagi
   mata dengan sensitivitas kontras rendah TANPA satu pun galat. Ini kegagalan
   senyap paling umum di antarmuka gelap, dan lembar S1 ada justru untuk
   menguncinya. --garis (#1E2732, 1,27:1) lebih parah lagi dan DILARANG di sini.
   -------------------------------------------------------------------------- */
.bidang { display: block; margin-bottom: var(--r4); }
.bidang > label, .label { display: block; font-size: var(--t-kecil); font-weight: 600; margin-bottom: var(--r2); }
.kolom {
  width: 100%; min-height: 52px; padding: var(--r3);
  /* 52px, bukan 48px: DESIGN.md paket ini meminta kolom dan tombol minimal 52px.
     16px WAJIB: di bawah itu Safari iOS ikut memperbesar layar saat kolom difokus. */
  font-size: var(--t-isi); font-family: var(--f-isi); color: var(--tinta);
  background: var(--kertas); border: 1px solid var(--garis-kendali);   /* 3,20:1 di atas kartu */
  border-radius: var(--radius-kecil);                                  /* DESIGN.md: kolom 6px */
}
.kolom::placeholder { color: #86929F; }   /* 5,52:1 di atas --kertas */
textarea.kolom { min-height: 120px; resize: vertical; }
.bantuan { font-size: var(--t-kecil); color: var(--redup); margin-top: var(--r2); }
.bantuan-galat { color: var(--galat); font-weight: 600; }      /* 8,42:1 */
.bantuan-sukses { color: var(--sukses); font-weight: 600; }    /* 10,60:1 */
.kolom[aria-invalid="true"] { border-color: var(--galat); border-width: 2px; }
.kolom[disabled] { background: var(--nonaktif); color: var(--redup); cursor: not-allowed; }

/* Radio sebaris (W14: tiga pilihan dalam satu baris), target sentuh 48px penuh,
   dan yang terpilih ditandai border DAN alas, bukan warna titik saja. */
.pilihan { display: grid; gap: var(--r2); }
@media (min-width: 640px) { .pilihan { grid-auto-flow: column; grid-auto-columns: 1fr; } }
.pilihan label {
  display: flex; align-items: center; gap: var(--r2); min-height: 48px;
  padding: var(--r2) var(--r3); border: 1px solid var(--garis-kendali);
  border-radius: var(--radius); background: var(--kertas);
  font-size: var(--t-kecil); cursor: pointer;
}
/* accent-color menggambar isian kendali DAN centangnya PUTIH. Putih di atas biru
   #4C8DFF cuma 3,20:1, jadi kendalinya --tinta (yang di sini nyaris putih) dengan
   centang gelap: peramban memilih warna centang yang kontras terhadap isian, dan
   di atas #EEF3F8 ia menggambar centang gelap. */
.pilihan input { width: 20px; height: 20px; accent-color: var(--tinta); flex: none; }
.pilihan label:has(input:checked) { border-color: var(--aksen); border-width: 2px; background: var(--aksen-alas); }

/* Segmented control, padanan mobile untuk radio 2 sampai 3 opsi */
.segmen { display: flex; border: 1px solid var(--garis-kendali); border-radius: var(--radius); overflow: hidden; }
.segmen button {
  flex: 1; min-height: 48px; border: 0; background: var(--kertas); cursor: pointer;
  font-family: var(--f-isi); font-size: var(--t-kecil); font-weight: 600; color: var(--tinta);
}
.segmen button + button { border-left: 1px solid var(--garis-kendali); }
/* Tombol tersegmen terpilih: isian aksen, label --latar 14px bobot 600 (6,00:1),
   DITAMBAH garis dalam --latar 2px supaya keterpilihannya tidak hanya di warna. */
.segmen button[aria-pressed="true"] { background: var(--aksen); color: var(--latar);
                                      box-shadow: inset 0 0 0 2px var(--latar); }

/* -----------------------------------------------------------------------------
   17. PESAN DALAM HALAMAN, supaya implementasi tidak jatuh ke alert() peramban.
   Tidak pernah membawa makna lewat warna saja: selalu ada ikon dan kata.
   -------------------------------------------------------------------------- */
.pesan {
  display: flex; gap: var(--r3); align-items: flex-start;
  padding: var(--r3) var(--r4); border-radius: var(--radius);
  border-left: 4px solid; font-size: var(--t-kecil);
}
/* Tiap alas dihitung sendiri terhadap TINTA dan REDUP, bukan diwarisi: S3 menuntut
   tiap warna teks di dalam strip tetap ≥4,5:1 terhadap alas stripnya.
     galat-alas #2A1416      → tinta 15,55:1 · redup 7,24:1 · garis kiri 7,60:1
     peringatan-alas #2A2113 → tinta 14,19:1 · redup 6,61:1 · garis kiri 9,67:1
     sukses-alas #10241C     → tinta 14,57:1 · redup 6,79:1 · garis kiri 8,97:1
     aksen-alas #16233A      → tinta 14,08:1 · redup 6,56:1 · garis kiri 4,91:1 */
.pesan-galat { background: var(--galat-alas); border-color: var(--galat); color: var(--tinta); }
.pesan-peringatan { background: var(--peringatan-alas); border-color: var(--peringatan); color: var(--tinta); }
.pesan-sukses { background: var(--sukses-alas); border-color: var(--sukses); color: var(--tinta); }
.pesan-info { background: var(--aksen-alas); border-color: var(--aksen); color: var(--tinta); }
.pesan b { display: block; }
.pesan p { color: var(--redup); }        /* ≥6,56:1 di atas tiap alas di atas */

/* -----------------------------------------------------------------------------
   18. BAR TAB BAWAH (mobile), navigasi UTAMA di mobile, bukan hamburger
   -------------------------------------------------------------------------- */
.tab-bar {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 40;
  display: grid; grid-template-columns: repeat(5, 1fr);
  background: var(--kertas); border-top: 1px solid var(--garis-kendali);   /* 3,20:1 */
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.tab-bar a {
  display: grid; place-items: center; gap: 2px;
  min-height: 56px; padding: var(--r2) var(--r1);
  text-decoration: none; color: var(--redup); font-size: var(--t-label);
}
/* Tab aktif dibedakan warna DAN tebal DAN garis atas, bukan warna saja. Garis
   atasnya AKSEN (6,00:1), S8 memintanya begitu, dan di sini permintaan itu bisa
   dituruti apa adanya. Ikon di dalam pil beraksen memakai --latar (6,00:1). */
.tab-bar a[aria-current="page"] { color: var(--aksen); font-weight: 600; box-shadow: inset 0 3px 0 0 var(--aksen); }
.tab-bar a[aria-current="page"] .ikon { background: var(--aksen); color: var(--latar);
                                        border-radius: 999px;
                                        padding: 2px 10px; box-sizing: content-box; width: 20px; }
.tab-bar .ikon { width: 22px; height: 22px; }
@media (min-width: 900px) { .tab-bar { display: none; } body { padding-bottom: 0; } }

/* -----------------------------------------------------------------------------
   19. BOTTOM SHEET, padanan mobile untuk dropdown
   -------------------------------------------------------------------------- */
/* Scrim di tema gelap harus LEBIH GELAP dari latar halaman, kalau tidak ia tidak
   terbaca sebagai lapisan sama sekali. rgba(4,7,10,.82) ada di 1,05:1 terhadap
   --latar bila dipadatkan, tugasnya memisahkan, bukan mengontraskan teks. */
.lapis { position: fixed; inset: 0; z-index: 50; background: rgba(4,7,10,.82); display: grid; align-items: end; }
.lapis[hidden] { display: none; }
.sheet {
  background: var(--kertas); border-radius: 8px 8px 0 0;
  padding-bottom: env(safe-area-inset-bottom, 0px); max-height: 80vh; overflow-y: auto;
}
.sheet-pegangan { width: 36px; height: 4px; background: var(--garis-kendali); opacity: .5;
                  border-radius: 2px; margin: var(--r3) auto; }
.sheet-kepala { display: flex; align-items: center; gap: var(--r3); padding: 0 var(--r4) var(--r3);
                border-bottom: 1px solid var(--garis-kendali); }
.sheet-kepala h3 { font-size: 1rem; }
.sheet-tutup { margin-left: auto; min-width: 48px; min-height: 48px; display: grid; place-items: center;
               background: none; border: 0; cursor: pointer; color: var(--tinta); }
@media (min-width: 900px) {
  .lapis { align-items: center; justify-items: center; }
  .sheet { border-radius: var(--radius); max-width: 480px; width: 100%; }
}

/* Lightbox portofolio (S4). Tiap kendalinya ≥48px, diatur di .lightbox-aksi. */
.lightbox img { width: 100%; max-height: 70vh; object-fit: contain; background: #05080C; }
.lightbox-gambar { position: relative; }
.lightbox-aksi { display: flex; flex-wrap: wrap; align-items: center; gap: var(--r3);
                 padding: var(--r4); border-top: 1px solid var(--garis); }
.lightbox-aksi .tombol-ikon { min-width: 48px; min-height: 48px; display: grid; place-items: center;
                              background: none; border: 1px solid var(--garis-kendali);
                              border-radius: var(--radius-kecil); color: var(--tinta); cursor: pointer; }
.lightbox-hitung { font-variant-numeric: tabular-nums; font-size: var(--t-kecil); color: var(--redup); }

/* -----------------------------------------------------------------------------
   20. SKELETON MEMUAT, bukan spinner, supaya bentuk halaman sudah terbaca
   -------------------------------------------------------------------------- */
.tulang { background: var(--nonaktif); border-radius: var(--radius); position: relative; overflow: hidden; }
.tulang::after {
  content: ""; position: absolute; inset: 0;
  /* .65 warisan tema terang akan menyala seperti lampu di atas #1B2531. Diturunkan
     ke .06, cukup untuk terbaca sebagai denyut, tidak cukup untuk menyilaukan. */
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.06), transparent);
  animation: kilau 1.4s ease-in-out infinite;
}
@keyframes kilau { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
.tulang-baris { height: 14px; margin-bottom: var(--r2); }
.tulang-judul { height: 28px; width: 60%; margin-bottom: var(--r3); }
.tulang-foto { aspect-ratio: 4 / 3; }

/* -----------------------------------------------------------------------------
   21. HALAMAN GALAT
   DITINJAU ULANG UNTUK KEDELAPAN KALINYA, dan kali ini hasilnya BERBEDA dari
   situs 08 dan 14, karena hitungannya, bukan karena disalin. Biru #4C8DFF di
   atas latar ada di 6,00:1, jadi angka "404" bisa berupa TEKS beraksen langsung,
   persis seperti yang diminta S6 ("a large 404 in accent #4C8DFF"). Di situs 14
   permintaan yang sama terpaksa diubah jadi blok isian karena emasnya 2,24:1.

   ⚠️ CACAT WARISAN YANG DIPERBAIKI DI SINI, dan wajib tetap begini: di situs
   02–06 aturannya ditulis `.galat-halaman p { color: var(--redup); }` SESUDAH
   `.galat-kode`. Spesifisitasnya 0,1,1 lawan 0,1,0, jadi angka 404/500 diam-diam
   mewarisi --redup. Bentuk yang benar memakai `:not(.galat-kode)`, dan yang
   membuktikannya BUKAN membaca kode ini melainkan menghitung warna hasil render.
   Di situs ini angka galat diukur ulang dari peramban dan keluar #4C8DFF di atas
   #0B0F14 = 6,00:1, yaitu aksen yang memang dimaksud.
   -------------------------------------------------------------------------- */
.galat-kode { font-family: var(--f-judul); font-weight: 700; font-size: clamp(3rem, 12vw, 6rem);
              line-height: 1.1; display: block; color: var(--aksen); }   /* 6,00:1 */
/* ⚠️ `:not(.galat-kode)` WAJIB TETAP ADA. Tanpa itu `.galat-halaman p` (0,1,1)
   mencuri `.galat-kode` (0,1,0) dan angka galat diam-diam mewarisi --redup, terukur 2,56:1 di situs 06, 2,60:1 di 04, 1,88:1 di 08. Di sini akibatnya akan
   berbeda tapi tetap salah: 8,02:1 yang "lulus" namun bukan aksen yang dimaksud,
   jadi cacatnya jadi TAK TERLIHAT SAMA SEKALI. Dihitung dulu sebelum ditambal,
   sesuai catatan situs 01 tempat cacat yang sama justru menyelamatkan halaman. */
.galat-halaman p:not(.galat-kode) { color: var(--redup); }
.galat-aksi { display: flex; flex-wrap: wrap; gap: var(--r3); justify-content: center; }

/* Anak yang dipusatkan lewat place-items:center TIDAK melar: lebarnya lahir dari
   isinya sendiri, jadi satu paragraf panjang bisa melewati viewport, terukur
   10px di 320px pada situs 02, dan yang dilaporkan meluber cuma "p" tanpa kelas,
   mustahil ditebak dari kode. max-width:100% saja TIDAK menutupnya; grid-nya yang
   dicabut. Halaman galat di sini karena itu blok sejak awal, bukan grid. */
.galat-halaman { display: block; text-align: center; padding-block: var(--r9);
                 max-width: 56ch; margin-inline: auto; }
.galat-halaman > * + * { margin-top: var(--r4); }
.galat-halaman > * { max-width: 100%; }

/* -----------------------------------------------------------------------------
   22. FOOTER
   Pola situs 14 (`background: var(--tinta)`) MUSTAHIL disalin ke sini: di tema
   gelap --tinta nyaris putih, dan footer putih di bawah halaman gelap adalah
   kesalahan yang paling cepat terlihat. Alasnya #0F141B, sedikit di bawah --latar
   supaya batasnya terbaca tanpa garis: tinta 16,56:1, tautan #A8B5C2 8,85:1,
   aksen 5,77:1.
   -------------------------------------------------------------------------- */
.footer { background: #0F141B; color: var(--tinta); padding-block: var(--r7); margin-top: var(--r7);
          border-top: 1px solid var(--garis); }
.footer a { color: #A8B5C2; text-decoration: none; font-size: var(--t-kecil); }  /* 8,85:1 */
.footer a:hover { color: var(--tinta); text-decoration: underline; }
.footer h4 { font-size: var(--t-label); letter-spacing: .08em; text-transform: uppercase; margin-bottom: var(--r3); }
.footer li { margin-bottom: var(--r2); }
.footer-atas { display: grid; gap: var(--r5); }
@media (min-width: 768px) { .footer-atas { grid-template-columns: 2fr 1fr 1fr 1fr; gap: var(--r6); } }
.footer-tentang { color: #A8B5C2; font-size: var(--t-kecil); margin-top: var(--r3); max-width: 40ch; }
.footer-bawah {
  margin-top: var(--r6); padding-top: var(--r4); border-top: 1px solid #232D3A;
  display: flex; flex-wrap: wrap; gap: var(--r3); justify-content: space-between;
  font-size: var(--t-kecil); color: #A8B5C2;
}
/* Aksen 5,77:1 di atas alas footer, jadi cincin fokus di sini tidak perlu diubah, tapi ditulis eksplisit supaya tidak ada yang menggantinya jadi putih karena
   kebiasaan situs 14. */
.footer :focus-visible { outline-color: var(--aksen); }

/* -----------------------------------------------------------------------------
   23. UTILITAS
   -------------------------------------------------------------------------- */
.hanya-layar-baca {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.tumpuk-2 { display: grid; gap: var(--r2); }
.tumpuk-3 { display: grid; gap: var(--r3); }
.tumpuk-4 { display: grid; gap: var(--r4); }
.redup { color: var(--redup); }
.kecil { font-size: var(--t-kecil); }
@media (min-width: 900px) { .hanya-mobile { display: none !important; } }
@media (max-width: 899px) { .hanya-desktop { display: none !important; } }

/* -----------------------------------------------------------------------------
   24. GERAK DIKURANGI, hormati preferensi sistem
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
  .tulang::after { animation: none; }
}

/* -----------------------------------------------------------------------------
   25. FOTO, DI SITUS INI FOTONYA ADALAH TANGKAPAN LAYAR KE-14 SITUS SENDIRI

   Tidak ada foto generatif sama sekali di paket ini, jadi seluruh rambu merek
   nyata dan potret kembar yang berlaku di situs 01–14 tidak punya pekerjaan di
   sini. Yang ada: 14 tangkapan layar (aset/karya-01.jpg … karya-14.jpg) yang
   dirakit sendiri dengan Playwright dari situs/01-… sampai situs/14-…, dimuat di
   lebar 1440 dan dipotret sesudah hurufnya benar-benar termuat, lalu diperkecil
   ke 640×444 dan disimpan sebagai JPEG (27–39 KB per berkas, 479 KB total untuk
   keempat belasnya).

   Kebenarannya DIBUKTIKAN, bukan diasumsikan: tiap halaman diukur panjang teks
   yang benar-benar dirender (7.149–16.575 karakter), jumlah gambar yang
   naturalWidth-nya lebih dari nol, dan daftar face huruf yang statusnya benar-benar
   "loaded", BUKAN document.fonts.check, yang menjawab true juga saat keluarga
   hurufnya tidak ada karena huruf cadangan dihitung termuat. Hasilnya lalu dilihat
   sebagai dua contact sheet.

   Kartu portofolio yang memuatnya WAJIB membawa .cip-contoh "desain contoh", lihat rambu di kepala berkas.
   -------------------------------------------------------------------------- */
.gambar-lebar, .foto-kosong {
  aspect-ratio: 16 / 10; width: 100%; object-fit: cover;
  border-radius: var(--radius); border: 1px solid var(--garis); background: var(--nonaktif);
}
.foto-kosong {
  display: grid; place-content: center; justify-items: center; gap: var(--r2);
  color: var(--redup);                                  /* 5,23:1 di atas --nonaktif */
  background-color: var(--nonaktif);
  background-image: linear-gradient(var(--garis) 1px, transparent 1px),
                    linear-gradient(90deg, var(--garis) 1px, transparent 1px);
  background-size: 16px 16px;
}
.foto-kosong span {
  font-family: var(--f-isi); font-weight: 600; font-size: var(--t-label);
  letter-spacing: .08em; background: var(--kertas); color: var(--tinta); padding: 2px var(--r2);
  border-radius: 4px; border: 1px solid var(--garis-kendali); text-align: center;
}

.potret {
  width: 100%; aspect-ratio: 1 / 1; object-fit: cover;
  border-radius: var(--radius); border: 1px solid var(--garis); margin-bottom: var(--r3);
}
.potret-inisial {
  display: grid; place-items: center; background: var(--aksen-alas); color: var(--tinta);
  font-family: var(--f-judul); font-weight: 600; font-size: 1.75rem; letter-spacing: .04em;
}

/* Tombol pembungkus foto yang bisa diperbesar, tetap terlihat sebagai gambar */
.foto-tombol { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: zoom-in;
               position: relative; }
.foto-tombol img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover;
                   border-radius: var(--radius); border: 1px solid var(--garis); }

/* Pengganti peta, tidak memuat peta pihak ketiga, jadi tidak ada pelacak. */
.peta {
  display: grid; place-content: center; justify-items: center; gap: var(--r3);
  aspect-ratio: 4 / 3; border-radius: var(--radius); border: 1px solid var(--garis);
  color: var(--redup); text-align: center; padding: var(--r4);
  background-color: var(--nonaktif);
  background-image: linear-gradient(var(--garis) 1px, transparent 1px),
                    linear-gradient(90deg, var(--garis) 1px, transparent 1px);
  background-size: 24px 24px;
}
.peta span { font-size: var(--t-kecil); max-width: 28ch; }

/* Dua kolom di layar lebar, satu kolom di mobile. align-items:start WAJIB di
   semuanya, tanpa itu kolom yang isinya pendek ikut melar setinggi tetangganya
   dan yang terlihat pengunjung adalah kartu setengah kosong sepanjang layar. */
@media (min-width: 900px) {
  [data-dua-kolom] { grid-template-columns: 1fr 1fr; align-items: start; }
  /* Bedah (W5): tangkapan layar besar di kiri, enam keputusan di kanan. */
  .bedah-tata { grid-template-columns: 1fr 1fr; gap: var(--r6) !important; align-items: start; }
  /* Perawatan (W12): daftar yang rusak di kiri, kartu paket di kanan. */
  .perawatan-tata { grid-template-columns: 1.15fr 1fr; gap: var(--r6) !important; align-items: start; }
  /* Formulir (W14): formulir di kiri, kartu tiga baris kanal di kanan. */
  .formulir-tata { grid-template-columns: 1.25fr 1fr; gap: var(--r6) !important; align-items: start; }
}

/* -----------------------------------------------------------------------------
   26. PENCARI, baris kendali mendatar untuk penyaring dan pelacak
   -------------------------------------------------------------------------- */
.pencari { display: grid; gap: var(--r3); align-items: end; margin-bottom: var(--r6); }
@media (min-width: 900px) { .pencari { grid-template-columns: repeat(3, minmax(0,1fr)) auto; } }
.pencari .bidang { margin: 0; }
.pencari .tombol { min-height: 48px; }

/* -----------------------------------------------------------------------------
   27. RAPI-RAPI DI BAWAH 900px, semuanya hanya terlihat setelah dirender
   -------------------------------------------------------------------------- */
@media (max-width: 899px) {
  /* Tombol navbar membungkus jadi dua baris dan mendesak wordmark sampai nyaris
     tak terbaca. Di mobile aksi ini juga sudah ada di bar tab bawah, jadi di sini
     ia cukup ringkas: tanpa ikon, padding lebih rapat, dan label 12px.
     Di bawah 900px tombol ini berubah jadi tombol bergaris. Alasannya BUKAN
     kontras huruf (--latar di atas biru 6,00:1 lulus di ukuran apa pun) melainkan
     bobot visual: isian biru penuh di bar setinggi 64px membuat wordmark kalah,
     dan tombol bergaris bertinta 17,22:1 menyelesaikannya. */
  .navbar .tombol-utama { background: none; color: var(--tinta);
                          border-color: var(--garis-kendali); }
  .navbar .tombol-utama:hover { background: var(--sentuh); }
  .navbar .tombol { padding-inline: var(--r3); white-space: nowrap; font-size: var(--t-label); }
  .navbar .tombol .ikon { display: none; }
  .wordmark { font-size: 0.75rem; letter-spacing: .04em; }

  /* Aksi utama melebar penuh supaya lebarnya seragam dan mudah dijangkau jempol. */
  .hero-aksi { flex-direction: column; align-items: stretch; }
  .hero-aksi .tombol { width: 100%; }
}

/* -----------------------------------------------------------------------------
   28. PONSEL SEMPIT (≤ 380px), iPhone SE dan Android kecil
   Label tab turun ke 11px dan padding dirapatkan. Wordmark paket ini tiga kata,
   jadi ia ikut mengecil.
   -------------------------------------------------------------------------- */
@media (max-width: 380px) {
  :root { --tepi: 1rem; }
  .tab-bar a { font-size: 0.6875rem; padding-inline: 2px; min-width: 0; }
  .tab-bar a > :last-child { max-width: 100%; overflow-wrap: anywhere; text-align: center; line-height: 1.15; }
  .tab-bar .ikon { width: 20px; height: 20px; }
  .wordmark { font-size: 0.6875rem; }

  /* TERUKUR, bukan ditaksir: di 320px wordmark panjang plus tombol berlabel panjang
     yang TIDAK boleh membungkus mendorong lebar halaman. Label tombol didiktekan
     brief dan diuji verbatim, jadi yang dicabut nowrap-nya. Wordmark paket ini satu
     kata dan pendek, tapi tombolnya berlabel "Konsultasi gratis" yang panjang,
     jadi tombolnya tetap diberi izin membungkus. */
  .navbar .tombol { white-space: normal; text-align: center; line-height: 1.2;
                    padding-inline: var(--r2); }
}


/* -----------------------------------------------------------------------------
   29. IKON KOTAK, bingkai lembut untuk ikon penyortir niat dan kartu layanan.
   Alasnya --aksen-alas (#16233A) dan ikonnya AKSEN: biru di atas alas itu 4,91:1,
   jauh di atas lantai 3:1 untuk ikon fungsional. Di situs 14 pola yang sama
   memakai ikon bertinta karena emasnya cuma 2,09:1 di atas alas lembutnya.
   -------------------------------------------------------------------------- */
.ikon-kotak {
  width: 44px; height: 44px; flex: none; display: grid; place-items: center;
  border-radius: var(--radius-kecil); background: var(--aksen-alas); color: var(--aksen);
  margin-bottom: var(--r3);
}
.ikon-kotak-redup { background: var(--nonaktif); color: var(--redup); }   /* 6,46:1 */

/* -----------------------------------------------------------------------------
   30. BARIS INFO BERIKON, dipakai untuk baris kanal kontak dan catatan.
   -------------------------------------------------------------------------- */
.info-baris { display: flex; gap: var(--r3); align-items: flex-start;
              font-size: var(--t-kecil); color: var(--redup); }
.info-baris .ikon { margin-top: 2px; }
.info-baris b { color: var(--tinta); }

/* Cip berbentuk KALIMAT. Cip biasa memakai huruf besar semua dan itu benar untuk
   satu-dua kata; untuk satu kalimat penuh ia berhenti terbaca. */
.cip-kalimat {
  display: inline-flex; align-items: center; gap: var(--r2);
  text-transform: none; letter-spacing: 0; font-size: var(--t-kecil);
  padding: var(--r2) var(--r4);
}
.hero .cip { margin-bottom: var(--r3); }

/* Pesan "ini desain contoh" yang muncul sesudah tombol yang memang tidak punya
   tujuan nyata. Tersembunyi sampai ditekan, dan isinya ditulis JS. */
.pesan-contoh { margin-top: var(--r3); }

@media (min-width: 1100px) { .kisi-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
@media (min-width: 900px) and (max-width: 1099px) { .kisi-5 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 560px) and (max-width: 899px) { .kisi-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
a.kartu { text-decoration: none; display: block; }
a.kartu:hover { background: var(--sentuh); }
button.kartu { width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer; }
button.cip-garis { font-family: var(--f-isi); cursor: pointer; }
/* 🔴 Tautan berpanah yang sebenarnya TOMBOL, dan tanpa aturan ini ia keluar
   sebagai tombol BAWAAN peramban. Terukur dari peramban: alasnya #F0F0F0
   (abu-abu TERANG di atas kartu gelap), hurufnya Arial, dan warna aksennya
   jatuh ke 2,81:1 di atas alas terang itu. Ketiga audit hijau saat itu, karena
   teksnya benar dan lebar halamannya tidak berubah sedikit pun. Elemen yang
   dipilih karena semantiknya (tombol yang menjawab di dalam halaman, bukan
   href="#" yang melompat ke puncak) tetap harus dinolkan gayanya. */
button.tautan-panah {
  background: none; border: 0; padding: 0; cursor: pointer;
  font-family: var(--f-isi); font-size: var(--t-kecil); font-weight: 600;
  color: var(--aksen);            /* 5,46:1 di atas kartu, terukur ulang sesudah ditambal */
  text-align: left;
}

/* Baris kepala bagian yang punya aksi di kanannya. */
.kepala-aksi { display: flex; flex-wrap: wrap; gap: var(--r4);
               align-items: end; justify-content: space-between; margin-bottom: var(--r5); }
.kepala-aksi .kepala-bagian { margin-bottom: 0; }

/* Unggah berkas, dipakai di lembar komponen. Bordernya --garis-kendali (3,51:1),
   bukan --garis: ia area yang bisa diklik. */
.unggah {
  display: grid; place-items: center; gap: var(--r2); text-align: center;
  padding: var(--r6) var(--r4); border: 2px dashed var(--garis-kendali);
  border-radius: var(--radius); background: var(--kertas); cursor: pointer;
  font-size: var(--t-kecil); color: var(--redup);
}
.unggah:hover { background: var(--sentuh); }

/* =============================================================================
   31. KOMPONEN KHAS PAKET 15, studio yang memublikasikan harga dan karyanya
   Semua warna di bawah memakai token yang rasionya sudah tertulis di bagian 1.
   Tidak ada satu pun tempat yang memakai PUTIH di atas isian aksen, dan tidak ada
   satu pun kendali yang memakai --garis (1,27:1) sebagai bordernya.
   ========================================================================== */

/* 31a. KARTU PORTOFOLIO, kartu terpenting di halaman ini.
   Tiap kartu WAJIB membawa .cip-contoh "desain contoh" di sudut kiri atas
   gambarnya. Itu bukan hiasan melainkan syarat kejujuran: ke-14 perusahaan itu
   tidak ada, dan tanpa label ini kartunya terbaca sebagai daftar klien.
   Kotak gambarnya `position: relative`, WAJIB, karena cip di dalamnya berposisi
   absolut dan tanpa blok penampung ia mengambil <body>, LOLOS dari pemangkasan
   overflow, lalu menarik lebar dokumen melewati layar. */
.kisi-karya { display: grid; gap: var(--r5); }
@media (min-width: 640px)  { .kisi-karya { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (min-width: 1000px) { .kisi-karya { grid-template-columns: repeat(3, minmax(0,1fr)); } }
.kisi-karya > * { min-width: 0; }

.kartu-karya { padding: 0; overflow: hidden; display: flex; flex-direction: column;
               position: relative; background: var(--kertas);
               border: 1px solid var(--garis); border-radius: var(--radius); }
.karya-gambar { position: relative; overflow: hidden; border-bottom: 1px solid var(--garis); }
.karya-gambar img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; object-position: top center;
                    display: block; background: var(--nonaktif); }
.karya-isi { padding: var(--r4); display: flex; flex-direction: column; gap: var(--r1);
             flex: 1; min-width: 0; }
.karya-isi h3 { font-size: 1.0625rem; }
.karya-usaha { font-size: var(--t-kecil); color: var(--redup); }
.karya-isi .tautan-panah { margin-top: var(--r3); align-self: flex-start; }

/* Label "desain contoh", 12px, isian aksen, teks --latar (6,00:1). Ia sengaja
   TIDAK redup dan TIDAK tembus pandang: label kejujuran yang sulit dibaca adalah
   label yang tidak dibaca. */
.cip-contoh {
  position: absolute; top: var(--r2); left: var(--r2); z-index: 1;
  background: var(--aksen); color: var(--latar);          /* 6,00:1 */
  font-size: var(--t-label); font-weight: 700; letter-spacing: .02em;
  padding: 3px var(--r2); border-radius: 4px;
}

/* 31b. KARTU STATISTIK MASALAH (W3), angka sangat besar beraksen.
   Aksen sebagai TEKS sah di sini: 5,46:1 di atas --kertas, di atas ambang 4,5:1
   untuk teks normal apalagi untuk angka sebesar ini. */
.angka-besar { display: block; font-family: var(--f-judul); font-weight: 700;
               font-size: clamp(2rem, 4.6vw, 2.75rem); line-height: 1.1;
               font-variant-numeric: tabular-nums; color: var(--aksen); }   /* 5,46:1 di kartu */
.statistik-label { display: block; margin-top: var(--r2); font-weight: 600; }
.statistik-sumber { display: block; margin-top: auto; padding-top: var(--r3);
                    font-size: var(--t-label); color: var(--redup);         /* 7,30:1 */
                    border-top: 1px solid var(--garis); }
.kartu-statistik { display: flex; flex-direction: column; gap: var(--r1); }

/* 31c. KARTU HARGA, tiga berdampingan, yang tengah ditandai garis aksen 1px DAN
   cip "Paling banyak dipilih". Dua penanda, bukan warna saja. */
.kisi-harga { display: grid; gap: var(--r5); align-items: start; }
@media (min-width: 900px) { .kisi-harga { grid-template-columns: repeat(3, minmax(0,1fr)); } }
.kisi-harga > * { min-width: 0; }
.kartu-harga { display: flex; flex-direction: column; gap: var(--r3); height: 100%;
               padding: var(--r5); }
.kartu-harga-sorot { border-color: var(--aksen); }        /* 6,00:1 terhadap latar */
.harga-cip { align-self: flex-start; }
.harga-angka { font-family: var(--f-judul); font-weight: 700;
               font-size: clamp(1.75rem, 3.6vw, 2.25rem); line-height: 1.15;
               font-variant-numeric: tabular-nums; display: block; }
.harga-satuan { font-size: var(--t-kecil); color: var(--redup); font-weight: 400; }
.harga-ket { color: var(--redup); font-size: var(--t-kecil); }
.kartu-harga .tombol { margin-top: auto; }
.kartu-harga h3 { font-size: 1.125rem; }

/* Daftar centang, ikon --sukses (10,60:1 di atas latar, 9,65:1 di atas kartu).
   Katanya tetap ditulis lengkap; ikon tidak pernah jadi satu-satunya pembawa makna. */
.daftar-cek { display: grid; gap: var(--r2); }
.daftar-cek li { display: flex; gap: var(--r3); align-items: flex-start;
                 font-size: var(--t-kecil); }
.daftar-cek .ikon { color: var(--sukses); margin-top: 2px; }

/* 31d. DAFTAR "YANG ANDA PEGANG" (W9), dua kolom, delapan baris. */
.kisi-diterima { display: grid; gap: var(--r4); }
@media (min-width: 760px) { .kisi-diterima { grid-template-columns: repeat(2, minmax(0,1fr)); } }
.kisi-diterima > * { min-width: 0; }
.diterima-baris { display: flex; gap: var(--r3); align-items: flex-start; }
.diterima-baris .ikon { color: var(--aksen); margin-top: 2px; }   /* 6,00:1 */
.diterima-baris b { display: block; }
.diterima-baris span { display: block; font-size: var(--t-kecil); color: var(--redup); }

/* 31e. BARIS "YANG TIDAK KAMI KERJAKAN" (W10), ikon dalam nada REDUP, sesuai
   brief. Redup 8,02:1 di atas latar, jadi ia tetap terbaca; yang diredupkan
   bobot visualnya, bukan keterbacaannya. */
.tolak-baris { display: flex; gap: var(--r4); align-items: flex-start;
               padding-block: var(--r4); border-bottom: 1px solid var(--garis); }
.tolak-baris:last-child { border-bottom: 0; }
.tolak-baris .ikon { color: var(--redup); margin-top: 3px; flex: none; }
.tolak-baris b { display: block; font-size: 1.0625rem; font-family: var(--f-judul); }
.tolak-baris p { color: var(--redup); font-size: var(--t-kecil); margin-top: var(--r1); }

/* 31f. KARTU ORANG, situs ini tidak memajang wajah siapa pun, jadi potretnya
   .potret-inisial: dua huruf di atas --aksen-alas (tinta 14,08:1). Menggunakan
   foto orang nyata untuk tim yang belum tentu berfoto adalah kelas kesalahan yang
   sama dengan memakai logo klien yang tidak ada. */
.potret { width: 100%; aspect-ratio: 1 / 1; object-fit: cover;
          border-radius: var(--radius); border: 1px solid var(--garis); margin-bottom: var(--r3); }
.potret-inisial {
  display: grid; place-items: center; aspect-ratio: 1 / 1; margin-bottom: var(--r3);
  border-radius: var(--radius); border: 1px solid var(--garis);
  background: var(--aksen-alas); color: var(--tinta);      /* 14,08:1 */
  font-family: var(--f-judul); font-weight: 700; font-size: 1.75rem; letter-spacing: .04em;
}
.kartu-orang h3 { font-size: 1.0625rem; }
.kartu-orang .peran { font-size: var(--t-kecil); color: var(--aksen); font-weight: 600; }  /* 5,46:1 */

/* 31g. BARIS PERINGATAN PERAWATAN (W12), ikon "warning" dalam nada amber.
   #F5C26B ada di 11,73:1 terhadap latar; "muted amber" versi tema terang
   (#7A4B00, 6,99:1 di situs 14) akan menghilang total di sini. */
.rusak-baris { display: flex; gap: var(--r3); align-items: flex-start;
               padding-block: var(--r3); border-bottom: 1px solid var(--garis); }
.rusak-baris:last-child { border-bottom: 0; }
.rusak-baris .ikon { color: var(--peringatan); margin-top: 3px; flex: none; }  /* 11,73:1 */
.rusak-baris b { display: block; }
.rusak-baris span { display: block; font-size: var(--t-kecil); color: var(--redup); }

/* 31h. KARTU BEDAH (W5), daftar bernomor enam keputusan. Nomornya lingkaran
   beraksen dengan angka --latar (6,00:1). */
.bedah-daftar { display: grid; gap: var(--r5); counter-reset: bedah; }
.bedah-daftar li { display: flex; gap: var(--r4); align-items: flex-start; counter-increment: bedah; }
.bedah-daftar li::before {
  content: counter(bedah); flex: none;
  width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center;
  background: var(--aksen); color: var(--latar);           /* 6,00:1 */
  font-family: var(--f-judul); font-weight: 700; font-size: var(--t-kecil);
  font-variant-numeric: tabular-nums;
}
.bedah-daftar b { display: block; font-family: var(--f-judul); font-size: 1.0625rem; }
.bedah-daftar p { color: var(--redup); font-size: var(--t-kecil); margin-top: var(--r1); }
.bedah-gambar figcaption { margin-top: var(--r3); font-size: var(--t-kecil); color: var(--redup); }

/* 31i. PENYORTIR NIAT (W2), tiga kartu setara, tiap kartu berakhir di tautan
   berpanah. Panahnya IKON SVG, bukan aksara: U+2192 tidak ada di kedua huruf. */
.kartu-niat { display: flex; flex-direction: column; height: 100%; }
.kartu-niat .tautan-panah { margin-top: auto; padding-top: var(--r4); align-self: flex-start; }

/* 31j. KARTU KANAL KONTAK (W14), tiga baris ikon/label/nilai. */
.kanal-baris { display: flex; gap: var(--r3); align-items: flex-start;
               padding-block: var(--r3); border-bottom: 1px solid var(--garis); }
.kanal-baris:last-child { border-bottom: 0; }
.kanal-baris .ikon { color: var(--aksen); margin-top: 2px; flex: none; }
.kanal-baris b { display: block; font-size: var(--t-kecil); }
.kanal-baris span { display: block; color: var(--redup); font-size: var(--t-kecil); }

/* 31k. LEMBAR STATE, kolom nama keadaan di kiri, contohnya di kanan (S1, S2, S8).
   Nama keadaan HURUF BESAR 12px; itu lantai ukuran teks di berkas ini. */
.lembar-state { display: grid; gap: var(--r5); }
.state-baris { display: grid; gap: var(--r3); align-items: start;
               padding-bottom: var(--r5); border-bottom: 1px solid var(--garis); }
.state-baris:last-child { border-bottom: 0; }
@media (min-width: 760px) { .state-baris { grid-template-columns: 12rem minmax(0, 1fr); gap: var(--r5); } }
.state-nama { font-size: var(--t-label); letter-spacing: .1em; text-transform: uppercase;
              font-weight: 700; color: var(--redup); }                     /* 8,02:1 */
.state-isi { min-width: 0; }

/* =============================================================================
   32. PENYESUAIAN YANG LAHIR DARI MARKUP HALAMAN INI
   ========================================================================== */

/* Blok penampung untuk keturunan berposisi absolut. Tanpa ini, .hanya-layar-baca
   dan .cip-contoh yang berada di dalam kotak berpangkas mengambil blok penampung
   dari <body>, LOLOS dari pemangkasan, lalu menarik lebar dokumen melewati layar.
   Gejalanya cuma terlihat sesudah dirender, dan yang dilaporkan meluber justru
   elemen lain. */
.bagian, .pita-statistik, .bungkus, .kartu, .segmen, .daftar, .faq,
.kartu-karya, .karya-gambar, .navbar { position: relative; }

.hero-statistik div { display: flex; align-items: center; gap: var(--r2); }

/* Kendali tersegmen berbasis RADIO SUNGGUHAN, bukan <button> yang mati tanpa
   JavaScript (jebakan 7 di resep). Radionya disembunyikan secara visual, labelnya
   yang digambar. */
.segmen label { flex: 1; min-width: 0; display: grid; place-items: center;
                min-height: 48px; padding-inline: var(--r2); text-align: center;
                overflow-wrap: anywhere; cursor: pointer;
                font-size: var(--t-kecil); font-weight: 600;
                color: var(--tinta); background: var(--kertas); }
.segmen label + label { border-left: 1px solid var(--garis-kendali); }
.segmen input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.segmen label:has(input:checked) { background: var(--aksen); color: var(--latar);
                                   box-shadow: inset 0 0 0 2px var(--latar); }
.segmen label:focus-within { outline: 2px solid var(--aksen); outline-offset: -3px; }

/* Kisi enam kolom untuk kartu layanan dan ringkasan. */
@media (min-width: 640px)  { .kisi-6 { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (min-width: 1000px) { .kisi-6 { grid-template-columns: repeat(3, minmax(0,1fr)); } }

/* Hero halaman ini SATU KOLOM rata tengah (W1), bukan dua kolom seperti situs 14. */
.hero-tengah { display: block; text-align: center; max-width: 60ch; margin-inline: auto; }
.hero-tengah .hero-sub { margin-inline: auto; }
.hero-tengah .hero-aksi { justify-content: center; }
.hero-tengah .hero-statistik { justify-content: center; }
/* ⚠️ display:block, BUKAN grid place-items:center. Anak yang dipusatkan lewat
   place-items diukur dari isinya sendiri, jadi satu paragraf panjang meluber di
   320px dan max-width:100% TIDAK menutupnya, terukur di situs 02. */
.hero-tengah > * { max-width: 100%; }

/* Pemisah tipis antar-statistik hero (W1 minta "thin vertical rules"). Di bawah
   640px pemisahnya dicabut karena statistiknya menumpuk tegak dan garis tegak di
   antara baris yang menumpuk terbaca sebagai cacat. */
@media (min-width: 640px) {
  .hero-statistik { gap: 0; }
  .hero-statistik > div { padding-inline: var(--r5); border-left: 1px solid var(--garis-kendali); }
  .hero-statistik > div:first-child { border-left: 0; padding-left: 0; }
}

/* Dropdown asli. `appearance:none` DILARANG di sini: tanpa panah bawaan peramban,
   kotak ini berhenti terbaca sebagai dropdown, dan U+25BC tidak dijamin ada di
   kedua huruf. Yang disetel hanya warnanya, supaya daftar pilihannya ikut gelap. */
select.kolom { color-scheme: dark; }

/* Baris tautan footer memakai .wordmark juga, ukurannya di footer lebih besar
   sedikit supaya ia terbaca sebagai penutup, bukan sebagai tautan. */
.footer .wordmark { font-size: 1.0625rem; color: var(--tinta); display: inline-block; }
.footer .wordmark:hover { text-decoration: none; }

/* Bagian yang alasnya dibedakan supaya galeri portofolio terbaca sebagai blok
   tersendiri. #0F141B sama dengan alas footer: tinta 16,56:1, redup 7,76:1. */
.bagian-gelap { background: #0F141B; }

/* Tabel di lembar komponen: kepala tabelnya --sentuh, dan di tema gelap itu
   nyaris tak berbeda dari kartu, jadi ia diberi garis bawah --garis-kendali. */
.tabel-bungkus th { border-bottom: 1px solid var(--garis-kendali); }
