Identity & media
People, pictures, and page openers — heroes, avatars, icons, and a row that scrolls.
Hero
.k-hero is a section with extra vertical
breathing room for the top of a page. __eyebrow is
a small mono line above the heading; __lead is a
larger, softer opening paragraph (used on this page's own
intro). Shown compactly here — a real hero takes the full band.
--center centers the hero text and the lead along
with it — for openers that sit in the middle rather than ranged
left.
Eyebrow · small mono line
A hero heading
The lead is larger and softer than body text, capped at a readable line length.
Eyebrow · small mono line
A centered hero
The lead centers too, still capped at a readable line length.
Markup
<section class="k-hero">
<div class="k-container">
<p class="k-hero__eyebrow">Eyebrow</p>
<h1>A hero heading</h1>
<p class="k-hero__lead">The opening paragraph.</p>
</div>
</section>
<!-- centered -->
<section class="k-hero k-hero--center">…</section>
Avatar
.k-avatar is a circle with initials in it;
--small and --large resize it, and
--square rounds the corners instead of the full
circle — for org logos or app marks. Put an
img inside instead of text and it fills the circle
(give the image an alt naming the person).
--ring draws a surface gap and an accent ring around
the circle — for the "active" or highlighted person in a row; the
--k-avatar-ring knob sets the ring color.
Markup
<span class="k-avatar k-avatar--small" aria-hidden="true">rd</span>
<span class="k-avatar" aria-hidden="true">rd</span>
<span class="k-avatar k-avatar--large" aria-hidden="true">rd</span>
<!-- ringed / active -->
<span class="k-avatar k-avatar--ring" aria-hidden="true">mk</span>
<!-- image variant -->
<span class="k-avatar"><img src="me.jpg" alt="R. Daiven"></span>
Avatar group
.k-avatar-group overlaps a row of avatars —
each after the first pulls in, and a surface-colored ring keeps
them readable where they stack. Order matters: later avatars sit
on top. If the group stands for "these people", say so in text
nearby; overlapping circles alone name nobody.
Markup
<span class="k-avatar-group">
<span class="k-avatar" aria-hidden="true">rd</span>
<span class="k-avatar" aria-hidden="true">mk</span>
<span class="k-avatar" aria-hidden="true">jt</span>
<span class="k-avatar" aria-hidden="true">+2</span>
</span>
Media object
.k-media puts a fixed thing (usually an avatar)
beside flowing text. The first child stays its own size;
.k-media__body takes the rest. The figure sits at the
top of the body by default; --center aligns it to the
body's vertical middle instead, and --reverse moves
it to the other side. The gap between them is the
--k-media-gap knob.
rdaiven · 2 days ago
The body wraps beside the avatar rather than under it, however long it runs.
mkeel · just now
Reversed and centered: the avatar sits on the right and lines up with the middle of this text.
Markup
<div class="k-media">
<span class="k-avatar" aria-hidden="true">rd</span>
<div class="k-media__body">
<p><strong>rdaiven</strong> <small>· 2 days ago</small></p>
<p>Comment text.</p>
</div>
</div>
<!-- figure on the right, centered against the body -->
<div class="k-media k-media--reverse k-media--center">…</div>
Icons
The .k-icon mechanism is in the core file; the
sixty-four named icons live in an optional
keel-icons.css (~40 KB min) — link it after
keel.css to use .k-icon--<name>,
or leave it out to keep the core lean. Either way, zero external
requests: each icon is an inline-SVG mask painted with
currentColor, so it takes the text color around it
and scales with the font-size, like a character.
They're decorative by default — add
aria-hidden="true"; if an icon carries meaning on
its own, give it role="img" and an
aria-label instead. There are no brand logos on
purpose — brands change, and shipping them would date the set;
bring your own SVGs for those.
Browse and copy the full set on the
Icons page — searchable, click-to-copy.
Decorative icons take aria-hidden="true"; a meaningful
icon-only control takes role="img" and an
aria-label.
Gallery
.k-gallery is a scroll-snap carousel — a row
that overflows sideways and snaps each item to the start edge.
Swipe on touch, scroll or shift-scroll with a wheel, tab through
the links inside; it's just scrolling, so it works everywhere.
Item width is the --k-gallery-item knob (default
min(78%, 20rem)). Where the platform supports
native ::scroll-marker dots — Chrome only, today —
they appear under the row for free; everywhere else you simply
get the row, no script, nothing broken.
Slide one
Swipe or scroll sideways — each card snaps to the start edge.
Slide two
Cards, images, anything — the children just need a width.
Slide three
In Chrome, native dots render below this row.
Slide four
The last one. Scroll back — it snaps the other way too.
Markup
<div class="k-gallery">
<div class="k-card">…</div>
<div class="k-card">…</div>
<div class="k-card">…</div>
</div>
<!-- narrower slides via the knob -->
<div class="k-gallery" style="--k-gallery-item: 14rem">…</div>