7 · Project: a landing page

Lesson 7 of 8 — build a complete, responsive, dark-mode landing page with everything you have learned.

2 min readv1

Time to build something real: a hero, a feature grid, a pricing section and a footer. Every piece uses the tokens and recipes from lessons 5 and 6.

The config#

TypeScript
// nibcss.config.ts
import { defineConfig } from "@nibcss/core";

export default defineConfig({
  darkMode: "class",
  tokens: {
    color: { brand: "#4F52D9", "brand-hover": "#3A3DBF", ink: "#0f172a", muted: "#64748b", border: "#e2e8f0" },
    space: { sm: "8px", md: "16px", lg: "24px", xl: "48px" },
    radius: { md: "10px", lg: "16px", pill: "999px" },
  },
  components: {
    container: "w=100%; mxw=1120px; mi=auto; px=$space.lg",
    section: "py=64px; md:py=96px",
    eyebrow: "fts=13px; ftw=700; txt=uppercase; lts=.08em; cl=$color.brand",
    h2: "fts=clamp(26px, 4vw, 40px); ftw=800; lts=-0.02em; lh=1.15",
    lead: "fts=18px; lh=1.7; cl=$color.muted; dark:cl=#94a3b8",
    card: "p=$space.lg; bdrd=$radius.lg; bgc=#fff; bd=1px solid $color.border; dark:bgc=#0f172a; dark:bd=1px solid #1e293b",
    btn: "d=inline-flex; ali=center; g=8px; p=12px 20px; bdrd=$radius.md; ftw=600; txd=none; cur=pointer; ts=all .15s",
    "btn-primary": "btn; bgc=$color.brand; cl=#fff; hover:bgc=$color.brand-hover",
    "btn-outline": "btn; bd=1px solid $color.border; cl=$color.ink; dark:cl=#fff; hover:bgc=#f8fafc; dark:hover:bgc=#1e293b",
  },
});

The hero#

HTML
<section nib="section; txa=center; bgi=radial-gradient(ellipse at top, #EEEFFE, transparent 60%); dark:bgi=radial-gradient(ellipse at top, #1e1b4b, transparent 60%)">
  <div nib="container; d=flex; flxd=column; ali=center; g=20px">
    <span nib="eyebrow">New · v1.1</span>
    <h1 nib="fts=clamp(34px, 6vw, 60px); ftw=800; lts=-0.03em; lh=1.05; mxw=16ch">
      Styles that live where your markup lives
    </h1>
    <p nib="lead; mxw=560px">Write CSS as attributes. Ship a static stylesheet. Keep one design system across every framework.</p>
    <div nib="d=flex; g=12px; flxw=wrap; jsc=center">
      <a nib="btn-primary" href="/start">Get started →</a>
      <a nib="btn-outline" href="/docs">Read the docs</a>
    </div>
  </div>
</section>

The feature grid#

HTML
⚡

Zero runtime

Static attributes compile at build time.

◎

Deterministic

Same rule, same class — everywhere.

✓

Helpful errors

Typos come with suggestions.

<div nib="d=grid; gtc=repeat(auto-fit, minmax(200px, 1fr)); g=16px; w=100%; mnw=320px">
  <div nib="card; p=20px">
    <div nib="w=36px; h=36px; bdrd=10px; bgc=#EEEFFE; cl=#4F52D9; d=grid; pli=center; ftw=800; mb=12px">⚡</div>
    <h3 nib="fts=16px; ftw=700; m=0">Zero runtime</h3>
    <p nib="fts=14px; cl=$color.ink-muted; mt=6px; lh=1.6">Static attributes compile at build time.</p>
  </div>
  <div nib="card; p=20px">
    <div nib="w=36px; h=36px; bdrd=10px; bgc=#ecfeff; cl=#0891b2; d=grid; pli=center; ftw=800; mb=12px">◎</div>
    <h3 nib="fts=16px; ftw=700; m=0">Deterministic</h3>
    <p nib="fts=14px; cl=$color.ink-muted; mt=6px; lh=1.6">Same rule, same class — everywhere.</p>
  </div>
  <div nib="card; p=20px">
    <div nib="w=36px; h=36px; bdrd=10px; bgc=#f0fdf4; cl=#16a34a; d=grid; pli=center; ftw=800; mb=12px">✓</div>
    <h3 nib="fts=16px; ftw=700; m=0">Helpful errors</h3>
    <p nib="fts=14px; cl=$color.ink-muted; mt=6px; lh=1.6">Typos come with suggestions.</p>
  </div>
</div>

Pricing with a highlighted plan#

HTML
Starter
$0
For side projects
POPULAR Team
$19
Per seat, per month
Enterprise
Custom
SLA and SSO
<div nib="d=grid; gtc=repeat(auto-fit, minmax(190px, 1fr)); g=16px; ali=stretch; w=100%; mnw=320px">
  <div nib="card; p=22px; d=flex; flxd=column; g=10px">
    <strong>Starter</strong>
    <div nib="fts=32px; ftw=800">$0</div>
    <span nib="fts=13px; cl=$color.ink-muted">For side projects</span>
  </div>
  <div nib="card; p=22px; d=flex; flxd=column; g=10px; bd=2px solid #4F52D9; bxsh=0 12px 32px rgba(79,82,217,.18); pos=relative">
    <span nib="pos=absolute; t=-11px; r=16px; p=2px 10px; bdrd=999px; bgc=#4F52D9; cl=#fff; fts=11px; ftw=700">POPULAR</span>
    <strong>Team</strong>
    <div nib="fts=32px; ftw=800">$19</div>
    <span nib="fts=13px; cl=$color.ink-muted">Per seat, per month</span>
  </div>
  <div nib="card; p=22px; d=flex; flxd=column; g=10px">
    <strong>Enterprise</strong>
    <div nib="fts=32px; ftw=800">Custom</div>
    <span nib="fts=13px; cl=$color.ink-muted">SLA and SSO</span>
  </div>
</div>
HTML
<footer nib="bdt=1px solid $color.border; dark:bdt=1px solid #1e293b; py=32px">
  <div nib="container; d=flex; flxd=column; md:flxd=row; jsc=space-between; g=16px; fts=14px; cl=$color.muted">
    <span>© 2026 Acme Inc.</span>
    <nav nib="d=flex; g=20px">
      <a nib="cl=inherit; txd=none; hover:cl=$color.brand" href="/privacy">Privacy</a>
      <a nib="cl=inherit; txd=none; hover:cl=$color.brand" href="/terms">Terms</a>
    </nav>
  </div>
</footer>

Review#

  • Recipes (container, section, card, btn-*) carry identity; per-page rules carry position.
  • Tokens keep colours consistent, and dark mode is a handful of dark: rules inside recipes.
  • No media queries were written by hand — clamp(), auto-fit and a few md: rules did it.

Next steps#