Bagian inilah jantung proyek: deretan tiga kartu paket — Pemula, Bisnis, dan Enterprise — yang menjadi alasan pengunjung membuka halaman ini. Kita butuh tata letak yang menampung tiga kartu berdampingan di desktop, menumpuk menjadi satu kolom di ponsel, dan tidak memerlukan media query apa pun untuk beradaptasi. Grid dengan pola auto-fit menjawabnya. Bersamaan, berkas styles.css bertambah dua seksi, dan untuk pertama kalinya halaman HTML muncul sebagai snapshot beranda.html — saat dipraktikkan, simpan isinya sebagai index.html.

Grid Otomatis dengan auto-fit dan minmax #

Aturan intinya hanya satu baris:

css
.galeri-harga {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}

Fungsi minmax(250px, 1fr) memberi tiap kolom lebar minimum 250 px dan maksimum satu bagian ruang kosong. Karena repeat() dipasangkan dengan auto-fit, browser menghitung sendiri berapa kolom yang muat: pada pembungkus 1080 px muat tiga atau empat kolom, pada tablet dua, pada ponsel satu. Jumlah kartu juga bebas berubah tanpa menyentuh CSS. Deklarasi align-items: stretch (nilai bawaan grid, kita tulis eksplisit untuk kejelasan) menyamakan tinggi seluruh kartu pada baris yang sama, dan gap mengatur jarak antarkartu.

Perkecil lebar jendela demo secara perlahan dan biarkan auto-fit menghitung ulang jumlah kolomnya sendiri. Adaptasi seperti ini biasanya dipaksakan dengan beberapa media query; pola auto-fit mencapainya dengan satu deklarasi.

Anatomi Kartu Harga #

Setiap kartu adalah article.kartu-harga dengan display: flex; flex-direction: column dan gap dari token. Susunannya dari atas ke bawah: nama paket, deskripsi satu kalimat, baris harga, daftar fitur, lalu tombol aksi. Kunci kenyamanan visualnya ada di tombol:

css
.kartu-harga .tombol {
  margin-top: auto;
  text-align: center;
}

Deklarasi margin-top: auto menyerap seluruh ruang kosong di atas tombol, sehingga tombol selalu menempel di dasar kartu meskipun daftar fitur antarpaket berbeda panjang. Tanpa trik ini, tombol kartu Pemula akan melayang lebih tinggi dibanding tombol kartu Bisnis.

Daftar fitur memakai list-style: none dan display: grid untuk jarak antarbutir, lalu tanda centang digambar lewat ::before berisi content: "✓" yang diberi warna --warna-sukses. Baris harga menyatukan angka besar dan satuan kecil dengan align-items: baseline, sehingga “/bulan” duduk rapi pada garis dasar angka, bukan menggantung di ujung atasnya.

Sedikit interaksi turut disiapkan: .kartu-harga memegang transisi untuk box-shadow dan transform, lalu :hover mengangkat kartu 2 px dan menaikkan bayangannya ke tingkat dua — kartu terlaris bahkan naik ke tingkat tiga. Gerak ini akan dimatikan lewat prefers-reduced-motion pada Bagian 5.

Menandai Paket Terlaris #

Paket Bisnis mendapat class modifier .kartu-harga--unggulan: border dua piksel berwarna --warna-utama, box-shadow tingkat dua yang lebih dalam, dan angka harga yang ikut berwarna indigo. Lencana “Terlaris” diposisikan absolut di tepi atas kartu:

css
.kartu-lencana {
  position: absolute; top: -12px; left: 50%;
  transform: translateX(-50%);
}

Deklarasi position: relative pada .kartu-harga menjadi payung positioning: tanpa itu, lencana akan mengukur diri terhadap halaman, bukan terhadap kartunya. Kombinasi top: -12px dengan translateX(-50%) menaruh lencana setengah menembus tepi atas dan tepat di tengah — pola yang umum dipakai untuk lencana notifikasi.

css
/* ============================================================
   Halaman Harga Layanan — stylesheet utama
   Urutan: token → base → kerangka halaman → galeri harga →
   kartu harga → tabel banding → tombol → saklar tagihan →
   responsif → gerak dan fokus
   ============================================================ */

/* ---------- 1. Design token ---------- */
:root {
  /* Warna semantik, tema terang */
  --warna-latar: #f8fafc;        --warna-permukaan: #ffffff;
  --warna-teks: #0f172a;         --warna-teks-lembut: #64748b;
  --warna-garis: #e2e8f0;        --warna-utama: #4f46e5;
  --warna-utama-pekat: #4338ca;  --warna-utama-kontras: #ffffff;
  --warna-utama-lembut: #e0e7ff; --warna-utama-tinta: #312e81;
  --warna-fokus: #1d4ed8;        --warna-sukses: #15803d;
  --warna-hemat-latar: #ccfbf1;  --warna-hemat-teks: #0f766e;
  --warna-lintasan: #cbd5e1;

  /* Skala spasi, basis empat dan delapan piksel */
  --jarak-1: 4px;  --jarak-2: 8px;
  --jarak-3: 12px; --jarak-4: 16px;
  --jarak-5: 24px; --jarak-6: 32px;
  --jarak-7: 48px; --jarak-8: 64px;

  /* Radius sudut */
  --radius-kecil: 8px; --radius: 12px;
  --radius-penuh: 999px;

  /* Elevasi bayangan, tiga tingkat */
  --bayangan-1: 0 1px 2px rgba(15, 23, 42, 0.06);
  --bayangan-2: 0 6px 16px rgba(79, 70, 229, 0.14);
  --bayangan-3: 0 16px 32px rgba(79, 70, 229, 0.18);

  /* Tipografi dan gerak */
  --font-dasar: system-ui, "Segoe UI", sans-serif;
  --tinggi-baris: 1.6;
  --durasi: 180ms; --pelunakan: ease-out;

  /* Kerangka halaman */
  --lebar-isi: 1080px;
}

/* ---------- 2. Base ---------- */
*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-dasar);
  line-height: var(--tinggi-baris);
  background-color: var(--warna-latar);
  color: var(--warna-teks);
}

h1, h2, h3, p, ul { margin: 0; }
img { display: block; max-width: 100%; }

/* ---------- 3. Kerangka halaman ---------- */
.pembungkus {
  max-width: var(--lebar-isi);
  margin-inline: auto;
  padding-inline: var(--jarak-4);
}

.laman-kepala {
  padding-block: var(--jarak-4);
  background-color: var(--warna-permukaan);
  border-bottom: 1px solid var(--warna-garis);
}

.kepala-baris {
  display: flex; align-items: center;
  justify-content: space-between;
  gap: var(--jarak-4); flex-wrap: wrap;
}

.brand { display: flex; align-items: center; gap: var(--jarak-2); }
.brand img { width: 36px; height: 36px; }
.brand-nama { font-size: 19px; font-weight: 800; }

.nav-kepala { display: flex; gap: var(--jarak-4); }
.nav-kepala a { color: var(--warna-teks-lembut); font-size: 15px; font-weight: 600; text-decoration: none; }
.nav-kepala a:hover { color: var(--warna-utama); }

.hero { padding-block: var(--jarak-7) var(--jarak-5); text-align: center; }
.judul-halaman { font-size: clamp(1.8rem, 4vw, 2.6rem); line-height: 1.2; letter-spacing: -0.02em; }
.pengantar { max-width: 56ch; margin: var(--jarak-3) auto 0; color: var(--warna-teks-lembut); }

.pilih-tagihan { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--jarak-3); margin-top: var(--jarak-5); }

.pilih-label { font-size: 15px; font-weight: 600; color: var(--warna-teks-lembut); }

.lencana-hemat { padding: 3px 12px; border-radius: var(--radius-penuh); background-color: var(--warna-hemat-latar); color: var(--warna-hemat-teks); font-size: 12.5px; font-weight: 700; }

.laman-kaki { margin-top: var(--jarak-8); padding-block: var(--jarak-5); background-color: var(--warna-permukaan); border-top: 1px solid var(--warna-garis); }

.kaki-baris { display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--jarak-2) var(--jarak-4); font-size: 13.5px; color: var(--warna-teks-lembut); }

/* ---------- 4. Galeri harga ---------- */
.galeri-harga { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--jarak-5); align-items: stretch; margin-top: var(--jarak-6); }

/* ---------- 5. Kartu harga ---------- */
.kartu-harga {
  position: relative;
  display: flex; flex-direction: column;
  gap: var(--jarak-3);
  padding: var(--jarak-5) var(--jarak-4);
  background-color: var(--warna-permukaan);
  border: 1px solid var(--warna-garis);
  border-radius: var(--radius);
  box-shadow: var(--bayangan-1);
  transition: box-shadow var(--durasi) var(--pelunakan), transform var(--durasi) var(--pelunakan);
}

.kartu-nama { font-size: 19px; font-weight: 800; }
.kartu-deskripsi { font-size: 14px; color: var(--warna-teks-lembut); }
.kartu-harga-baris { display: flex; align-items: baseline; gap: 6px; margin-top: var(--jarak-1); }
.kartu-angka { font-size: 2.1rem; font-weight: 800; letter-spacing: -0.02em; }
.kartu-angka--custom { font-size: 1.5rem; color: var(--warna-utama); }
.kartu-satuan { font-size: 14px; color: var(--warna-teks-lembut); }

.kartu-fitur { display: grid; gap: var(--jarak-2); margin-top: var(--jarak-1); padding: 0; list-style: none; font-size: 14.5px; }

.kartu-fitur li { position: relative; padding-left: 26px; }
.kartu-fitur li::before { content: "✓"; position: absolute; left: 0; color: var(--warna-sukses); font-weight: 700; }
.kartu-harga .tombol { margin-top: auto; text-align: center; }

.kartu-lencana { position: absolute; top: -12px; left: 50%; transform: translateX(-50%); padding: 4px 14px; border-radius: var(--radius-penuh); background-color: var(--warna-utama); color: var(--warna-utama-kontras); font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; }

.kartu-harga--unggulan {
  border: 2px solid var(--warna-utama);
  box-shadow: var(--bayangan-2);
}

.kartu-harga--unggulan .kartu-angka { color: var(--warna-utama); }

.kartu-harga:hover {
  box-shadow: var(--bayangan-2);
  transform: translateY(-2px);
}

.kartu-harga--unggulan:hover { box-shadow: var(--bayangan-3); }
html
<!DOCTYPE html>
<html lang="id">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Halaman Harga Layanan — LumbungKas</title>
  <link rel="icon" href="assets/logo.svg" type="image/svg+xml">
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <header class="laman-kepala">
    <div class="pembungkus kepala-baris">
      <div class="brand">
        <img src="assets/logo.svg" alt="Logo LumbungKas" width="36" height="36">
        <span class="brand-nama">LumbungKas</span>
      </div>
      <nav class="nav-kepala" aria-label="Navigasi utama">
        <a href="#paket">Paket</a>
        <a href="#perbandingan">Perbandingan</a>
      </nav>
    </div>
  </header>

  <main>
    <div class="pembungkus">
      <div class="hero">
        <h1 class="judul-halaman">Pilih paket yang pas untuk bisnismu</h1>
        <p class="pengantar">Pembukuan awan untuk UMKM: catat penjualan, kirim faktur, dan pantau laporan dari satu tempat. Semua paket bisa dicoba gratis 14 hari.</p>
        <div class="pilih-tagihan">
          <span class="pilih-label">Bulanan</span>
          <label class="saklar">
            <input type="checkbox" id="saklar-tagihan" role="switch" aria-checked="false">
            <span class="saklar-lintasan" aria-hidden="true"><span class="saklar-kenop"></span></span>
            <span class="sr-only">Ganti ke tagihan tahunan</span>
          </label>
          <span class="pilih-label">Tahunan</span>
          <span class="lencana-hemat">Hemat 2 bulan</span>
        </div>
      </div>

      <section class="galeri-harga" id="paket" aria-label="Daftar paket harga">
        <article class="kartu-harga">
          <h2 class="kartu-nama">Pemula</h2>
          <p class="kartu-deskripsi">Untuk usaha yang baru mulai mencatat transaksi.</p>
          <p class="kartu-harga-baris">
            <span class="kartu-angka" data-harga-bulanan="Rp49.000" data-harga-tahunan="Rp490.000">Rp49.000</span>
            <span class="kartu-satuan" data-satuan-bulanan="/bulan" data-satuan-tahunan="/tahun">/bulan</span>
          </p>
          <ul class="kartu-fitur">
            <li>1 pengguna</li>
            <li>30 faktur per bulan</li>
            <li>Laporan penjualan dasar</li>
            <li>Dukungan lewat surel</li>
          </ul>
          <a class="tombol tombol--garis" href="#">Mulai gratis 14 hari</a>
        </article>

        <article class="kartu-harga kartu-harga--unggulan">
          <span class="kartu-lencana">Terlaris</span>
          <h2 class="kartu-nama">Bisnis</h2>
          <p class="kartu-deskripsi">Untuk tim penjualan yang butuh laporan lengkap.</p>
          <p class="kartu-harga-baris">
            <span class="kartu-angka" data-harga-bulanan="Rp149.000" data-harga-tahunan="Rp1.490.000">Rp149.000</span>
            <span class="kartu-satuan" data-satuan-bulanan="/bulan" data-satuan-tahunan="/tahun">/bulan</span>
          </p>
          <ul class="kartu-fitur">
            <li>5 pengguna</li>
            <li>500 faktur per bulan</li>
            <li>Laporan keuangan lengkap</li>
            <li>Ekspor data akuntansi</li>
          </ul>
          <a class="tombol" href="#">Coba paket Bisnis</a>
        </article>

        <article class="kartu-harga">
          <h2 class="kartu-nama">Enterprise</h2>
          <p class="kartu-deskripsi">Untuk jaringan cabang dengan kebutuhan khusus.</p>
          <p class="kartu-harga-baris">
            <span class="kartu-angka kartu-angka--custom">Hubungi kami</span>
          </p>
          <ul class="kartu-fitur">
            <li>Pengguna tanpa batas</li>
            <li>Multi gudang dan multi cabang</li>
            <li>Integrasi khusus</li>
            <li>Dukungan prioritas</li>
          </ul>
          <a class="tombol tombol--garis" href="#">Jadwalkan demo</a>
        </article>
      </section>
    </div>
  </main>

  <footer class="laman-kaki">
    <div class="pembungkus kaki-baris">
      <span>LumbungKas — proyek latihan CSS</span>
      <span>Harga dalam Rupiah dan belum termasuk pajak</span>
    </div>
  </footer>
</body>
</html>

Ringkasan #

Galeri harga kini berdiri di atas grid auto-fit yang beradaptasi tanpa media query, kartu paket punya anatomi fleksibel dengan tombol yang menempel di dasar, dan varian --unggulan menonjolkan paket Bisnis lewat border, bayangan, dan lencana absolut. Markup halaman lengkap dengan saklar dan tiga kartu juga sudah tersedia sebagai beranda.html. Bagian berikutnya menambah seksi baru di bawah galeri: tabel perbandingan fitur.