Nº 154 of 520
Team hover portrait grid
A 3×2 Halden studio grid: six geometric SVG portraits, hover or focus unveils role, one-line bio, and a studio email.
Preview
Use it
Free to use · credit appreciated1 Once, in your project
npx skills add SusanAcharya/Design-Lounge 2 Then ask
Using the Design Lounge skill, build "Team hover portrait grid" (piece team-hover-portrait-grid) in my stack. Match its brief; restyle it onto my product's theme.
No skill? Paste the brief instead. It carries the numbers, tokens and behaviour.
<!-- Design Lounge Nº 154 · "Team hover portrait grid" · www.designlounge.live -->
# Team hover portrait grid
> **Build brief for a coding agent.** Rebuild this piece in the reader's stack. If they haven't said which stack, ask once, then default to semantic HTML + CSS + a little vanilla JS. Match the numbers below; don't "improve" them.
## What it is
A team section for **Halden**, an Oslo design studio. Six people sit in a 3×2 grid. Each cell is a geometric “portrait” — layered SVG rectangles, circles, and gradients in wine, gold, and cream — not photographs and not initials discs. At rest only the italic Bodoni name sits on the picture. Hover or keyboard focus drops a 78% ink veil over 320ms and reveals role (gold uppercase), a one-line bio, and a `mailto:` link. No JavaScript. The first frame is the six pictures with names already on them.
## Reference behaviour
1. Initial state: cream page `#F3EBE3`, 56px nav (italic “Halden” 22px Bodoni, Work / Index / Visit, wine `studio@halden.studio`). Lead: kicker “THE STUDIO · OSLO”, heading “Six people, one room”, right meta “HOVER A PORTRAIT”. Six portraits fill the remaining height. Names visible; role, bio, and email hidden (`max-height:0; opacity:0`).
2. Hover a card: `.veil` opacity 0 → 1 over 320ms; `.more` max-height 0 → 140px, opacity 0 → 1, translateY 8px → 0 over 320ms / 180ms. The SVG stays put underneath.
3. Focus-within a card (tab onto the card, then onto the email): same reveal. A 2px wine outline, 3px offset, sits on the card.
4. Hover the email: colour `--gold`. The underline is gold at rest (`text-decoration-color: var(--gold)`, offset 3px).
5. Leave the card: veil and `.more` reverse on the same clocks.
6. Tab order: brand → Work → Index → Visit → studio email → Mira card → Mira mail → Jonas card → Jonas mail → … through Henrik.
7. Reduced motion: veil and `.more` durations become 1ms; translate is forced to none. Reveal still happens.
## Structure
```
1280 × 800
┌──────────────────────────────────────────────────────────────────────┐
│ Halden Work Index Visit studio@halden.studio │ 56
│ THE STUDIO · OSLO HOVER A PORTRAIT │
│ Six people, one room │
│ ┌──────────────┬──────────────┬──────────────┐ │
│ │ Mira │ Jonas │ Amara │ │
│ │ (wine/gold │ (diag split) │ (offset sq) │ │
│ │ circles) │ │ │ │
│ ├──────────────┼──────────────┼──────────────┤ gap 14 │
│ │ Piet │ Clara │ Henrik │ │
│ │ (ellipse + │ (5 bands + │ (gold fall │ │
│ │ triangle) │ circle) │ + circle) │ │
│ └──────────────┴──────────────┴──────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
pad 56
```
… 134 more lines. Copy or download for the full brief. Loading the source…Brief
174 linesBuild brief for a coding agent. Rebuild this piece in the reader’s stack. If they haven’t said which stack, ask once, then default to semantic HTML + CSS + a little vanilla JS. Match the numbers below; don’t “improve” them.
What it is
A team section for Halden, an Oslo design studio. Six people sit in a 3×2 grid. Each cell is a geometric “portrait” — layered SVG rectangles, circles, and gradients in wine, gold, and cream — not photographs and not initials discs. At rest only the italic Bodoni name sits on the picture. Hover or keyboard focus drops a 78% ink veil over 320ms and reveals role (gold uppercase), a one-line bio, and a mailto: link. No JavaScript. The first frame is the six pictures with names already on them.
Reference behaviour
- Initial state: cream page
#F3EBE3, 56px nav (italic “Halden” 22px Bodoni, Work / Index / Visit, winestudio@halden.studio). Lead: kicker “THE STUDIO · OSLO”, heading “Six people, one room”, right meta “HOVER A PORTRAIT”. Six portraits fill the remaining height. Names visible; role, bio, and email hidden (max-height:0; opacity:0). - Hover a card:
.veilopacity 0 → 1 over 320ms;.moremax-height 0 → 140px, opacity 0 → 1, translateY 8px → 0 over 320ms / 180ms. The SVG stays put underneath. - Focus-within a card (tab onto the card, then onto the email): same reveal. A 2px wine outline, 3px offset, sits on the card.
- Hover the email: colour
--gold. The underline is gold at rest (text-decoration-color: var(--gold), offset 3px). - Leave the card: veil and
.morereverse on the same clocks. - Tab order: brand → Work → Index → Visit → studio email → Mira card → Mira mail → Jonas card → Jonas mail → … through Henrik.
- Reduced motion: veil and
.moredurations become 1ms; translate is forced to none. Reveal still happens.
Structure
1280 × 800
┌──────────────────────────────────────────────────────────────────────┐
│ Halden Work Index Visit studio@halden.studio │ 56
│ THE STUDIO · OSLO HOVER A PORTRAIT │
│ Six people, one room │
│ ┌──────────────┬──────────────┬──────────────┐ │
│ │ Mira │ Jonas │ Amara │ │
│ │ (wine/gold │ (diag split) │ (offset sq) │ │
│ │ circles) │ │ │ │
│ ├──────────────┼──────────────┼──────────────┤ gap 14 │
│ │ Piet │ Clara │ Henrik │ │
│ │ (ellipse + │ (5 bands + │ (gold fall │ │
│ │ triangle) │ circle) │ + circle) │ │
│ └──────────────┴──────────────┴──────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
pad 56
<nav>: italic.brand, three.links a,.ctamailto.<section aria-label="Studio team">:.lead+.grid..grid:repeat(3, 1fr)/1fr 1fr, gap 14px,flex:1.- Each person is a
<figure class="card" tabindex="0">:aria-hiddenSVG,.veil,<figcaption>withh2+.more(.role,.bio,.mail).
People, exact copy:
| Name | Role | Bio | Portrait | |
|---|---|---|---|---|
| Mira Solberg | Partner · type | Cuts the wordmarks. Taught letterpress at KHIO for six years. | mira@halden.studio | Wine diagonal + gold radial circle + dark circle + 2px cream rule |
| Jonas Keel | Partner · space | Plans the rooms. Last year: a reading hall in Bergen with no hanging signs. | jonas@halden.studio | Three-stop linear (ink → wine → gold) + dark polygon + cream circle |
| Amara Ndiaye | Art direction | Holds the still-life days. Shoots on 4×5 when the budget allows. | amara@halden.studio | Three offset squares (wine, gold, cream) on #2E1A20 |
| Piet Rask | Runs the Heidelberg on Thursdays. Keeps a book of every spoilage sheet. | piet@halden.studio | Radial ellipse + wine triangle on #3A2018 | |
| Clara Voss | Writing | Writes the long captions. Edited the Halden index for issues 11–18. | clara@halden.studio | Five 56px bands (ink, wine, rose, gold, cream) + cream circle |
| Henrik Dahl | Production | Schedules the press and the couriers. Answers the studio line after 16:00. | henrik@halden.studio | Gold-to-ink vertical gradient + wine circle + two cream hairlines |
SVG viewBox is 0 0 400 280 with preserveAspectRatio="xMidYMid slice" so the composition crops, it does not letterbox.
Tokens
:root {
--bg: #f3ebe3; /* page */
--ink: #1a1412; /* type */
--ink-2: #6a5a52; /* nav links */
--ink-3: #9a8a80; /* meta */
--line: #ddd2c6;
--wine: #5c2430; /* kicker, focus, card fallback */
--gold: #b8954a; /* role, mail hover, portrait metal */
--cream: #f7f0e8; /* name + bio on the veil */
--veil: rgba(26, 20, 18, .78);
--serif: "Bodoni Moda", Georgia, serif;
--sans: "Tenor Sans", Georgia, serif;
--nav-h: 56px;
--pad: 56px;
--gap: 14px;
--t-fast: 180ms;
--t-reveal: 320ms;
--ease: cubic-bezier(.2, .7, .2, 1);
--ease-out: cubic-bezier(.16, 1, .3, 1);
}
Tenor Sans is a display sans that sits next to Bodoni; do not substitute Inter.
Typography
| Role | Family | Size | Weight | Line-height | Tracking | Case |
|---|---|---|---|---|---|---|
| Body | Tenor Sans | 16px | 400 | 1.4 | 0 | sentence |
| Brand | Bodoni Moda italic | 22px | 500 | 1 | −0.02em | sentence |
| Nav links / CTA | Tenor Sans | 13px | 400 | 1 | +0.08–0.1em | UPPERCASE |
| Kicker | Tenor Sans | 12px | 400 | 1 | +0.16em | UPPERCASE |
| Heading | Bodoni Moda | 36px | 500 | 1 | −0.02em | sentence |
| Meta | Tenor Sans | 13px | 400 | 1 | +0.08em | UPPERCASE |
| Name | Bodoni Moda italic | 22px | 500 | 1 | −0.015em | sentence |
| Role | Tenor Sans | 12px | 400 | 1 | +0.12em | UPPERCASE |
| Bio / mail | Tenor Sans | 13px | 400 | 1.4 | 0 | sentence |
Bodoni optical size: "opsz" 22 on the brand and names, "opsz" 36 on the heading.
Motion
| Element | Trigger | Property | From → To | Duration | Easing |
|---|---|---|---|---|---|
.veil | hover / focus-within | opacity | 0 → 1 | 320ms | --ease |
.more | same | max-height | 0 → 140px | 320ms | --ease |
.more | same | opacity | 0 → 1 | 180ms | --ease |
.more | same | translateY | 8px → 0 | 320ms | --ease |
No portrait Ken Burns. No stagger on load. Reduced motion: 1ms durations, no translate.
States
- Card rest: portrait at full chroma, name on a transparent caption,
.morecollapsed, veil at 0. - Card hover / focus-within: veil 78% ink,
.moreopen, wine 2px outline when focused. - Mail hover: text
--gold. - Nav link hover: colour
--ink. - Nav / brand / CTA focus-visible: 2px wine, 3px offset.
- Cards have
tabindex="0"so the portrait itself is a stop, not only the mail link.
Accessibility
- Section labelled
aria-label="Studio team". - Portraits are
aria-hidden="true"; the name inh2is the accessible title. - Emails are real
<a href="mailto:…">. Do not fake them with click handlers. - Keyboard users get the same reveal via
:focus-withinwhen they tab to the card or the mail. - Contrast on the veil: cream
#F7F0E8onrgba(26,20,18,.78)over dark portraits is ≥ 8:1. Gold role on the veil is ≥ 4.6:1 at 12px uppercase. Wine kicker on cream is ~7:1. - Hit targets: each card is a large region; mail line is 13px with underline — keep the padding in
.moreso the tap row is ≥ 40px tall (10px margin-top + 13px + caption padding).
Responsive rules
- ≥ 1280: 3×2, pad 56px, heading 36px, gap 14px.
- 1024–1279: pad 28px, heading 28px. Grid stays 3×2.
- 768–1023: nav links hide; grid becomes 2×3. Cards keep the same reveal.
- < 640: 2×3 remains. Heading 26px. Do not drop to a single column in the demo frame; a host page may do so below 480.
Acceptance checklist
- First frame shows six geometric portraits and six italic names; roles and emails are not visible.
- Hover or focus on a card reveals role, one-line bio, and mailto over 320ms with a 78% ink veil.
- Exactly these six people and emails; all addresses end in
@halden.studio. - Portraits are inline SVG gradient compositions — no raster, no initials discs, no stock faces.
- Type pairing is Bodoni Moda + Tenor Sans only.
- Grid is 3×2 at 1280, gap 14px, filling the height under the lead.
- Focus-visible / focus-within draws a 2px
#5C2430ring, 3px offset. -
prefers-reduced-motion: reducereveals instantly; content is the same. - No JavaScript, no emoji, no dummy copy.
- Demo fills 1280×800 and starts with the piece header comment.
Implementation notes
Reveal with max-height, not display. display:none kills the fade and drops the name:
.more { max-height: 0; opacity: 0; overflow: hidden; transform: translateY(8px);
transition: max-height 320ms var(--ease), opacity 180ms var(--ease), transform 320ms var(--ease); }
.card:hover .more, .card:focus-within .more { max-height: 140px; opacity: 1; transform: none; }
Veil is a sibling, not a filter on the SVG. Filtering the SVG would muddy the gold. Stack: SVG (bottom) → .veil (z 1) → figcaption (z 2).
Slice, don’t letterbox. Each SVG uses preserveAspectRatio="xMidYMid slice" and the card is overflow:hidden so the composition crops as the cell grows.
Common mistakes: photograph avatars; a purple-to-blue portrait gradient; revealing the bio at rest so the hover has nothing to do; using Inter under Bodoni; article + figcaption without a figure (invalid). Cards must be <figure class="card">.
Details
- Palette
- Type
- Bodoni Moda · Tenor Sans
- Motion
- Subtle motion
- Build
- One session
- Tags
Studied
Don't Board MeA service with a next step. The headline can shout. The booking stays plain.
All sourcesOn the shelves