Chapter 06 / 12 · Wayfinding

Navigation. Finding the way.

How people move through the product and the site. Consistency here is trust.

6.1 Top nav

A pill-shaped horizontal bar with a brand dot, nav links, sign-in, and a pink CTA. Active item gets a 2px pink underline. Backdrop blurs when scrolled over content.

Marketing top nav

.tn

.tn {
  display: flex; align-items: center; gap: var(--s-5);
  padding: var(--s-4) var(--s-6);
  background: color-mix(in oklab, var(--bg-paper) 90%, transparent);
  backdrop-filter: saturate(140%) blur(10px);
  border: 1px solid var(--hair);
  border-radius: var(--r-pill);
  width: 100%; max-width: 960px;
  flex-wrap: wrap;
}
.tn-brand { display: inline-flex; align-items: center; gap: var(--s-2); font: 700 15px/1 var(--f-display); color: var(--fg); text-decoration: none; letter-spacing: -0.01em; }
.tn-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.tn-links { display: inline-flex; gap: var(--s-5); }
.tn-links a {
  color: var(--fg-soft); text-decoration: none;
  font: 500 13.5px/1 var(--f-body);
  padding: 6px 0; position: relative;
  transition: color var(--dur-2) var(--ease);
}
.tn-links a:hover { color: var(--fg); }
.tn-links a.is-active { color: var(--fg); }
.tn-links a.is-active::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -4px;
  height: 2px; background: var(--accent); border-radius: 2px;
}
.tn-spacer { flex: 1; }
.tn-link { color: var(--fg-soft); text-decoration: none; font: 500 13.5px/1 var(--f-body); padding: 6px 10px; }
.tn-link:hover { color: var(--fg); }
.tn-cta {
  background: var(--accent); color: var(--paper);
  font: 600 13.5px/1 var(--f-display);
  padding: 9px var(--s-4);
  border-radius: var(--r-pill);
  text-decoration: none;
  box-shadow: var(--sh-pink);
  transition: transform var(--dur-2) var(--ease);
}
.tn-cta:hover { transform: translateY(-1px); color: var(--paper); }

6.2 Side nav

Compact vertical nav for in-app surfaces. Sectioned headings in mono, active item gets a pink-soft pill fill.

Side nav

.sn

.sn {
  width: 240px;
  background: var(--bg-paper);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  padding: var(--s-5);
  display: flex; flex-direction: column; gap: 2px;
  font-family: var(--f-body);
}
.sn-brand { display: inline-flex; align-items: center; gap: var(--s-2); font: 700 14px/1 var(--f-display); padding: var(--s-2) var(--s-3) var(--s-4); }
.sn-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.sn-section { font: 500 10.5px/1 var(--f-mono); text-transform: uppercase; letter-spacing: 0.1em; color: var(--fg-faint); padding: var(--s-4) var(--s-3) var(--s-2); }
.sn-item {
  display: flex; align-items: center; gap: var(--s-3);
  padding: 8px var(--s-3);
  border-radius: var(--r-sm);
  font: 500 13.5px/1 var(--f-body);
  color: var(--fg-soft);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
.sn-item:hover { background: var(--bg-sunk); color: var(--fg); }
.sn-item.is-active {
  background: var(--accent-soft); color: var(--accent-text);
}
.sn-item.is-active svg { color: var(--accent-text); }
.sn-item > span:first-of-type { flex: 1; }
.sn-count { font-family: var(--f-mono); font-size: 11px; color: var(--fg-faint); font-weight: 500; }
.sn-item.is-active .sn-count { color: var(--accent-text); }

6.3 Tabs

Horizontal tab bar with pink underline for the active tab. Optional count chip sits right of the label. Tabs scroll horizontally on mobile.

Underline tabs

.tabs

Overview

The panel content matches the selected tab. Use Tab+arrow keys to navigate between tabs.

.tabs-wrap { width: 100%; } /* fluid — flows to the column width on wide layouts, internal overflow-x handles narrow */
.tabs {
  display: inline-flex; gap: 0;
  border-bottom: 1px solid var(--hair);
  width: 100%;
  overflow-x: auto;
  scrollbar-width: none;          /* Firefox: hide fat OS scrollbar */
  -ms-overflow-style: none;       /* legacy Edge / IE */
}
.tabs::-webkit-scrollbar { display: none; } /* Chrome / Safari */
.tab {
  appearance: none; background: transparent; border: 0;
  padding: 12px var(--s-4) 14px;
  font: 500 13.5px/1 var(--f-body); color: var(--fg-dim);
  cursor: pointer;
  position: relative; white-space: nowrap;
  transition: color var(--dur-2) var(--ease);
  display: inline-flex; align-items: center; gap: var(--s-2);
}
.tab:hover { color: var(--fg); }
.tab.is-active { color: var(--fg); }
.tab.is-active::after {
  content: ""; position: absolute; left: 10px; right: 10px; bottom: -1px;
  height: 2px; background: var(--accent); border-radius: 2px;
}
.tab-count {
  font-family: var(--f-mono); font-size: 11px; color: var(--fg-faint);
  padding: 2px 6px; background: var(--bg-sunk); border-radius: var(--r-xs);
}
.tab.is-active .tab-count { color: var(--accent-text); background: var(--accent-soft); }

.tabs-body { padding: var(--s-5) 0 0; }
.tabs-body-title { font: 600 15px/1.3 var(--f-display); margin: 0 0 var(--s-2); }
.tabs-body-text { font: 400 14px/1.55 var(--f-body); color: var(--fg-soft); margin: 0; }

6.5 Pagination

Two patterns: numbered pagination for long lists, a compact range indicator for dense UIs. Active page fills pink.

Pagination

.pag · .pag-compact

Showing 21–40 of 248
.pag { display: inline-flex; gap: 4px; align-items: center; }
.pag-btn {
  min-width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--fg-soft);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font: 500 13px/1 var(--f-mono);
  cursor: pointer;
  padding: 0 8px;
  gap: 4px;
  transition: background var(--dur-2) var(--ease), color var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease);
}
.pag-btn:hover { background: var(--bg-sunk); color: var(--fg); }
.pag-btn.is-active { background: var(--accent); color: var(--paper); }
.pag-arr { border-color: var(--hair); }
.pag-ellipsis { color: var(--fg-faint); padding: 0 4px; font-family: var(--f-mono); }

.pag-compact { display: inline-flex; align-items: center; gap: var(--s-2); font-size: 12.5px; color: var(--fg-soft); flex-wrap: wrap; }
.pag-compact strong { color: var(--fg); font-weight: 600; }
.pag-compact-divider { width: 1px; height: 16px; background: var(--hair); margin: 0 var(--s-2); }

6.7 Stepper

Vertical progress indicator for flows with clear stages — onboarding, setup, wizards. Done steps fill pink; the active step pulses with a soft ring.

Vertical stepper

.stepper

  1. Connect CRM
    HubSpot · connected
  2. Build your agent
    Tone · channels · guardrails
  3. 3
    Test conversations
    Simulate 20 inbound leads
  4. 4
    Launch
    Flip the switch
.stepper { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0; }
.step {
  display: grid; grid-template-columns: 32px 1fr;
  gap: var(--s-4);
  padding: var(--s-3) 0;
  position: relative;
}
.step:not(:last-child)::before {
  content: ""; position: absolute;
  top: 38px; bottom: -6px; left: 15px; width: 2px;
  background: var(--hair);
}
.step.is-done::before { background: var(--accent); }
.step-dot {
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--bg-paper); border: 2px solid var(--hair);
  display: inline-flex; align-items: center; justify-content: center;
  font: 600 13px/1 var(--f-mono); color: var(--fg-dim);
  position: relative; z-index: 1;
}
.step.is-done .step-dot { background: var(--accent); border-color: var(--accent); color: var(--paper); }
.step.is-active .step-dot { border-color: var(--accent); color: var(--accent-text); box-shadow: 0 0 0 4px var(--accent-soft); }
.step-name { font: 600 14.5px/1.3 var(--f-display); color: var(--fg); }
.step.is-done .step-name { color: var(--fg-soft); }
.step-meta { font: 400 12.5px/1.4 var(--f-mono); color: var(--fg-dim); }

6.9 Command-K bar

A global command palette triggered by ⌘K. Centred modal with search, grouped results, and keyboard hints. The fastest path through a dense product surface.

⌘K palette

.cmdk

Live-filtered list; arrow keys move selection; Enter executes; Esc closes. Group labels use mono uppercase.

⌘K
Leads
Actions
↑↓ navigate · open · Esc close
<div class="cmdk">
  <div class="cmdk-head">
    <input class="cmdk-input" placeholder="Search…" />
    <kbd class="cmdk-kbd">⌘K</kbd>
  </div>
  <div class="cmdk-group">
    <div class="cmdk-label">Leads</div>
    <button class="cmdk-row is-active">Acme Corp</button>
  </div>
</div>
.cmdk { width: 520px; max-width: 100%; background: var(--bg-paper);
  border: 1px solid var(--hair); border-radius: var(--r-lg);
  box-shadow: var(--sh-3); overflow: hidden; }
.cmdk-head { display:flex; align-items:center; gap:var(--s-3);
  padding: var(--s-4); border-bottom: 1px solid var(--hair); }
.cmdk-input { flex:1; border:0; background:transparent; font: 400 15px/1 var(--f-body); color: var(--fg); outline:none; }
.cmdk-kbd, .cmdk-row kbd { font: 600 11px/1 var(--f-mono); padding: 3px 6px;
  background: var(--bg-sunk); border: 1px solid var(--hair);
  border-radius: var(--r-xs); color: var(--fg-soft); }
.cmdk-group { padding: var(--s-2) 0; }
.cmdk-label { font: 500 11px/1 var(--f-mono); text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--fg-dim);
  padding: var(--s-2) var(--s-4); }
.cmdk-row { display:flex; justify-content:space-between; align-items:center;
  width:100%; padding: var(--s-3) var(--s-4); border:0;
  background:transparent; font: 400 14px/1 var(--f-body); color: var(--fg);
  text-align:left; cursor:pointer; }
.cmdk-row.is-active, .cmdk-row:hover { background: var(--accent-soft); color: var(--accent-text); }
.cmdk-foot { display:flex; gap:var(--s-3); padding: var(--s-3) var(--s-4);
  border-top: 1px solid var(--hair); background: var(--bg-sunk);
  font: 400 12px/1 var(--f-body); color: var(--fg-dim); }
.skip-link-demo { position: absolute; top: -100px; left: var(--s-4);
  padding: 10px 16px; background: var(--accent); color: var(--paper);
  border-radius: var(--r-sm); font: 600 14px/1 var(--f-body);
  text-decoration: none; z-index: 10; transition: top var(--dur-2) var(--ease); }
.skip-link-demo:focus-visible { top: var(--s-4); }

6.10 Industry bar

A slim taxonomy strip that sits directly below the top nav and above the hero on every top-level page. Answers the buyer's silent first question — is this for me? — in under half a second. Ink surface + mono uppercase text so it reads as taxonomy, not marketing copy. Each industry links to its own page; the current industry gets an accent-dot indicator. On mobile the strip scrolls horizontally with a fade-edge hint.

Default

.industry-bar

Eyebrow FOR + 6 industries + interpunct dividers. Current industry dot-marked. Use on the homepage and every Tier 1 use-case / compare page.

<nav class="industry-bar" role="navigation" aria-label="Industries">
  <div class="industry-bar-inner">
    <span class="eyebrow">For</span>
    <a href="/industries/mortgage" class="is-current">Mortgage</a>
    <span class="sep" aria-hidden="true">·</span>
    <a href="/industries/insurance">Insurance</a>
    <span class="sep" aria-hidden="true">·</span>
    <a href="/industries/solar">Solar</a>
    <span class="sep" aria-hidden="true">·</span>
    <a href="/industries/home-services">Home Services</a>
    <span class="sep" aria-hidden="true">·</span>
    <a href="/industries/auto">Auto</a>
    <span class="sep" aria-hidden="true">·</span>
    <a href="/industries/fintech">Fintech</a>
  </div>
</nav>
.industry-bar {
  background: var(--ink);
  color: color-mix(in oklab, var(--warm-3) 92%, transparent);
  border-bottom: 1px solid color-mix(in oklab, var(--paper) 8%, transparent);
  overflow-x: auto;
}
.industry-bar-inner {
  display: flex; align-items: center; justify-content: center;
  gap: var(--s-4); padding: 10px var(--s-6); white-space: nowrap;
}
.industry-bar a {
  font: 500 12px/1 var(--f-mono);
  text-transform: uppercase; letter-spacing: 0.08em;
  color: color-mix(in oklab, var(--warm-3) 85%, transparent);
  text-decoration: none; position: relative;
  transition: color 160ms var(--ease);
}
.industry-bar a:hover { color: var(--accent-text); }
.industry-bar a.is-current { color: var(--paper); }
.industry-bar a.is-current::after {
  content: ""; position: absolute; left: 50%; bottom: -4px;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--accent); transform: translateX(-50%);
}
@media (max-width: 820px) {
  .industry-bar-inner { justify-content: flex-start; }
  .industry-bar { mask-image: linear-gradient(to right, black calc(100% - 32px), transparent); }
}

Compact

.industry-bar.is-compact

Drops the FOR eyebrow and tightens padding. Use where the strip needs to feel secondary — e.g. inside a documentation chrome or on footer secondary nav.

<nav class="industry-bar is-compact" role="navigation" aria-label="Industries">
  <div class="industry-bar-inner">
    <a href="…">Mortgage</a>
    <span class="sep" aria-hidden="true">/</span>
    <!-- …5 more industries, divider between each -->
  </div>
</nav>

6.13 Anatomy of the top nav

  1. 1
    1. Pill shape
    border-radius: var(--r-pill);
  2. 2
    2. Backdrop
    backdrop-filter: saturate(140%) blur(10px);
  3. 3
    3. Brand dot
    box-shadow: 0 0 0 4px var(--accent-soft);
  4. 4
    4. Active underline
    height: 2px; background: var(--accent);
  5. 5
    5. CTA
    background: var(--accent); box-shadow: var(--sh-pink);