Dengan token di tangan, Bagian 2 baru benar-benar menulis komponen. Stylesheet tumbuh dari 71 baris menjadi sekitar dua ratus baris dan kini mencakup kerangka halaman, tombol, kartu dasar, serta empat variasinya. Halaman galeri sudah bisa dibuka di browser, meskipun kartu-kartunya masih tampak datar karena bayangan baru hadir di Bagian 3.
Kerangka Halaman dan Tombol #
.pembungkus memusatkan konten dengan max-width: var(--lebar-isi) dan margin-inline: auto, ditambah padding samping 16 px agar konten tidak menempel layar sempit. .laman-kepala memberi latar permukaan dan garis bawah pada header, sementara .kepala-baris memakai flexbox dengan justify-content: space-between dan flex-wrap: wrap agar logo dan tombol tema saling menjauh namun rapi saat terlipat. .laman-kaki dan .kaki-baris mengulang pola serupa untuk footer.
Bagian paling penting adalah .galeri-kartu: grid dengan repeat(auto-fit, minmax(240px, 1fr)). Kolom muncul otomatis sesuai lebar layar tanpa media query sama sekali, dan gap: 24px memberi jarak antarkartu. Semua warna kerangka ini juga sudah memanggil token: latar halaman dari --warna-latar, permukaan header dan footer dari --warna-permukaan, garis pemisah dari --warna-garis. Tidak ada satu pun kode hex baru di bagian ini — kontrak yang dijaga sampai akhir proyek, dan tema gelap pada Bagian 5 mengandalkan disiplin yang sama. Tombol ditata pada grup .tombol: font: inherit mewarisi huruf halaman sehingga tombol tidak tampak asing, cursor: pointer menandai kemampuan klik, dan hover menggelapkan latar ke --warna-utama-pekat. Varian .tombol--sekunder menukar latar tebal menjadi --warna-utama-lembut dengan teks pekat.
Anatomi Kartu Dasar #
.kartu adalah flexbox vertikal dengan gap: 12px dan padding 16 px. Anak-anaknya punya peran jelas: .kartu-lencana memakai align-self: flex-start agar pil tidak melar penuh; .kartu-media memakai aspect-ratio: 16 / 10 sehingga bidang gambar tetap proporsional tanpa berkas gambar nyata, diisi gradient cokelat sebagai placeholder; .kartu-judul, .kartu-teks, dan .kartu-meta mengurus isi; .kartu-aksi menutup kartu.
Kunci kecil yang sering dibutuhkan ada di .kartu-aksi { margin-top: auto; }: pada flexbox vertikal, margin otomatis menyerap sisa ruang sehingga baris harga dan tombol selalu menempel di dasar kartu, sekalipun teks kartu sebelah lebih panjang. Inilah yang membuat tinggi kartu dalam satu baris grid terasa seragam.
Empat Variasi #
Variasi dibangun dengan kelas modifier, bukan dengan menyalin kartu. .kartu--produk hanya mengubah lencananya menjadi latar --warna-aksen beraksen oranye dengan teks putih, lewat selector turunan .kartu--produk .kartu-lencana. .kartu--artikel diubah dari elemen <a>: text-decoration: none dan color: inherit membuat tautan terlihat seperti kartu, dan metanya dorong ke dasar dengan pola margin-top: auto yang sama.
.kartu--profil memakai align-items: center dan text-align: center agar seluruh isi terpusat, lalu .kartu-avatar menampilkan inisial dalam lingkaran gradient 72 px memakai display: grid; place-items: center. .kartu--statistik menonjolkan angka: .kartu-angka berukuran 34 px dengan bobot 800, dan .kartu-tren menjadi pil kecil yang warnanya bergantung arah, hijau untuk --naik dan merah untuk --turun, mengambil token status dari Bagian 1.
/* ============================================================
Koleksi Kartu UI — stylesheet utama
Urutan: token → base → kerangka halaman → tombol → kartu
→ varian → elevasi → tipografi → state → tema gelap
============================================================ */
/* ---------- 1. Design token ---------- */
:root {
/* Warna semantik, tema terang */
--warna-latar: #f6f1e7; --warna-permukaan: #ffffff;
--warna-teks: #2a2118; --warna-teks-lembut: #6d5c48;
--warna-garis: #e4d9c6; --warna-utama: #7a4a21;
--warna-utama-pekat: #5c3517; --warna-utama-kontras: #ffffff;
--warna-utama-lembut: #f0e2cf; --warna-aksen: #b3541e;
--warna-sukses: #1f7a4d; --warna-bahaya: #b3372b;
--warna-fokus: #1d4ed8;
/* 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: 6px; --radius: 12px;
--radius-penuh: 999px;
/* Elevasi bayangan, tiga tingkat */
--bayangan-1: 0 1px 2px rgba(42, 33, 24, 0.08);
--bayangan-2: 0 4px 12px rgba(42, 33, 24, 0.14);
--bayangan-3: 0 12px 28px rgba(42, 33, 24, 0.18);
/* Skala tipografi */
--font-dasar: system-ui, "Segoe UI", sans-serif;
--ukuran-teks-kecil: 0.8125rem;
--ukuran-teks-sedang: 0.9375rem;
--ukuran-teks-dasar: 1rem;
--ukuran-teks-subjudul: 1.25rem;
--ukuran-teks-judul: 1.5rem;
--ukuran-angka: 2.25rem;
--tinggi-baris: 1.55;
--jejak-huruf-lebar: 0.08em;
/* Gerak */
--durasi-cepat: 120ms; --durasi: 200ms; --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, figure { margin: 0; }
img { display: block; max-width: 100%; }
/* ---------- 3. Kerangka halaman ---------- */
.pembungkus {
max-width: var(--lebar-isi);
margin-inline: auto;
padding-inline: 16px;
}
.laman-kepala {
padding-block: 24px;
background-color: var(--warna-permukaan);
border-bottom: 1px solid var(--warna-garis);
}
.kepala-baris {
display: flex; align-items: center;
justify-content: space-between;
gap: 16px; flex-wrap: wrap;
}
.brand { display: flex; align-items: center; gap: 12px; }
.brand img { width: 40px; height: 40px; }
.brand-nama { font-size: 20px; font-weight: 700; }
.laman-utama { padding-block: 48px 64px; }
.section-judul { font-size: 28px; font-weight: 800; }
.pengantar { margin-top: 8px; max-width: 65ch; color: var(--warna-teks-lembut); font-size: 15px; }
.pamer-token {
display: flex; flex-wrap: wrap;
gap: 12px 24px; margin-top: 24px;
padding: 16px; background-color: var(--warna-permukaan);
border: 1px solid var(--warna-garis); border-radius: 12px;
}
.token { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.token-contoh { width: 24px; height: 24px; border-radius: 6px; border: 1px solid var(--warna-garis); }
.token-nama { color: var(--warna-teks-lembut); }
.galeri-kartu {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 24px; margin-top: 32px;
}
.laman-kaki {
background-color: var(--warna-permukaan);
border-top: 1px solid var(--warna-garis);
}
.kaki-baris {
display: flex; justify-content: space-between;
flex-wrap: wrap; gap: 8px 16px;
padding-block: 24px; font-size: 13.5px;
color: var(--warna-teks-lembut);
}
/* ---------- 4. Tombol ---------- */
.tombol {
display: inline-block;
padding: 9px 18px; border: none; border-radius: 6px;
background-color: var(--warna-utama);
color: var(--warna-utama-kontras);
font: inherit; font-weight: 600; cursor: pointer;
}
.tombol:hover { background-color: var(--warna-utama-pekat); }
.tombol--sekunder { background-color: var(--warna-utama-lembut); color: var(--warna-utama-pekat); }
.tombol--sekunder:hover { background-color: var(--warna-garis); }
/* ---------- 5. Kartu ---------- */
.kartu {
display: flex; flex-direction: column;
gap: 12px; padding: 16px;
background-color: var(--warna-permukaan);
border: 1px solid var(--warna-garis); border-radius: 12px;
}
.kartu-lencana {
align-self: flex-start;
padding: 4px 12px; border-radius: var(--radius-penuh);
background-color: var(--warna-utama-lembut); color: var(--warna-utama-pekat);
font-size: 11.5px; font-weight: 700;
}
.kartu--produk .kartu-lencana { background-color: var(--warna-aksen); color: #ffffff; }
.kartu-media {
aspect-ratio: 16 / 10;
border-radius: 8px;
background: linear-gradient(135deg, #d8a26a 0%, #7a4a21 100%);
}
.kartu-judul { font-size: 20px; line-height: 1.3; font-weight: 700; }
.kartu-teks { font-size: 14.5px; color: var(--warna-teks-lembut); }
.kartu-meta {
display: flex; align-items: center;
gap: 8px; font-size: 12.5px;
color: var(--warna-teks-lembut);
}
.kartu-aksi {
margin-top: auto;
display: flex; align-items: center;
justify-content: space-between; gap: 8px;
}
.kartu-harga { font-size: 16px; font-weight: 700; color: var(--warna-utama-pekat); }
/* ---------- 6. Varian kartu ---------- */
.kartu--artikel { color: inherit; text-decoration: none; }
.kartu--artikel .kartu-meta { margin-top: auto; padding-top: 4px; }
.kartu--profil { align-items: center; text-align: center; }
.kartu-avatar {
width: 72px; height: 72px;
display: grid; place-items: center;
border-radius: var(--radius-penuh);
background: linear-gradient(135deg, #b3541e, #7a4a21);
color: #ffffff; font-size: 26px; font-weight: 700;
}
.kartu-peran { font-size: 13px; color: var(--warna-teks-lembut); }
.kartu-angka { font-size: 34px; font-weight: 800; line-height: 1.1; }
.kartu-tren { align-self: flex-start; padding: 2px 10px; border-radius: var(--radius-penuh); font-size: 12.5px; font-weight: 700; }
.kartu-tren--naik { color: var(--warna-sukses); }
.kartu-tren--turun { color: var(--warna-bahaya); }Ringkasan #
Bagian ini membangun semuanya yang terlihat: kerangka halaman, galeri grid otomatis, tombol primer dan sekunder, kartu dasar beserta lencana, media, meta, dan aksi, lalu empat varian lewat kelas modifier. Pola yang patut dibawa pulang: satu kartu dasar plus modifier jauh lebih mudah dirawat daripada banyak kartu yang mirip, dan margin-top: auto adalah cara paling sederhana menempelkan aksi ke dasar kartu.