Design Lounge
Install

Nº 115 of 520

Giant email, click to copy

A 200px Anton address fills the contact page; click copies it, flashes the page black, and scrambles the type to COPIED TO CLIPBOARD.

Preview

Open full size
1280 × 800 · 9.4 KB · 127 lines

Use it

Free to use · credit appreciated

1 Once, in your project

npx skills add SusanAcharya/Design-Lounge

2 Then ask

Using the Design Lounge skill, build "Giant email, click to copy" (piece contact-giant-email-copy) 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.

Brief

201 lines

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 full-viewport contact section for a sound-and-spatial studio (“Ferro Works”). The email HI@FERRO.WORK is the page: 200px condensed Anton, one line, flush left. Clicking it copies hi@ferro.work, inverts the whole page to black-on-cream for 1.6s, and runs a glyph scramble that resolves to COPIED TO CLIPBOARD then back to the address. A pill that says “Copy ↗” replaces the cursor over the address. The feeling is loud, physical, poster-like: 2px rules, four-column meta, a 52px inverted ticker of services. The detail worth copying is the fit-to-width resize — the display size is computed from a hidden probe so “COPIED TO CLIPBOARD” never overflows, even though it is longer than the email.

Reference behaviour

  1. Initial state: orange field #FF4F1A. Top strip of four cells (studio, cities + live Lisbon clock, booking, response time). Giant address. Four contact cells. Black ticker rolling services.
  2. Hovering the address: custom cursor hidden; a black pill “Copy ↗” tracks 14px down-right of the pointer; a 14px black underline wipes left → right in 420ms (scaleX 0 → 1, origin left).
  3. Clicking the address copies hi@ferro.work (lowercase) via navigator.clipboard.writeText, with a textarea + execCommand('copy') fallback. aria-live="assertive" announces “Copied hi@ferro.work to clipboard” (or the failure string with the address spoken).
  4. On success: body gets .flash (background --ink, colour --paper); the address gets .copied (type and underline become --paper); chip text becomes “Copied”; glyphs scramble to COPIED TO CLIPBOARD over 720ms.
  5. After 1600ms hold, flash and .copied drop; chip returns to “Copy ↗”; glyphs scramble back to HI@FERRO.WORK over 640ms. Further clicks during the hold restart the timeout.
  6. Clicking a data-copy link in the grid (phone, press, jobs) copies that string, swaps the link text to “Copied” for 1400ms, and announces via the same live region. Studio address is not copyable.
  7. Lisbon clock (#clock) formats Europe/Lisbon as Lisbon HH:MM with en-GB, 2-digit hour and minute, and refreshes every 30s.
  8. Display size: font-size = min(260px, 200px * mail.clientWidth / probeWidth) so the current string always fits. Recalculate on font load and resize.
  9. Ticker: duplicated phrase list scrolls translateX(-50%) over 38s linear infinite.
  10. Reduced motion: scramble snaps to the target string; ticker animation is none; transitions 1ms. Pointer-coarse (hover:none): native pointer on the address, chip hidden.

Structure

1280 × 800  body grid: auto / 1fr / auto / auto   overflow hidden
│  pad-x 40px, 2px rules
┌────────────┬────────────┬────────────┬────────────┐  top, border-bottom 2px
│ FERRO WORKS│ LISBON /   │ NOW BOOKING│ RESPONSE   │  18/14 pad, uppercase
│ Sound +    │ ROTTERDAM  │ Projects   │ Under 24 h │  13px Space Mono
│ spatial…   │ Lisbon HH:MM│ from Feb 2027│ Mon–Fri │
├────────────┴────────────┴────────────┴────────────┤
│  CONTACT — THE FASTEST WAY IN          CLICK TO COPY   kick  uppercase │
│  HI@FERRO.WORK                              ~200px Anton / .86         │
│  (underline 14px at bottom 6px, scaleX 0 until hover)                  │
├────────────┬────────────┬────────────┬────────────┤  grid, border-top
│ NEW BUSINESS│ PRESS     │ CAREERS    │ STUDIO     │  h4 12/700 +0.06em
│ Inês Prado  │ Tom van   │ Two open   │ Rua do     │
│ +351 21…    │ Dijk      │ roles      │ Açúcar 88  │
├────────────┴────────────┴────────────┴────────────┤
│ WRITE TO US ◆ INSTALLATIONS ◆ SONIC BRANDING ◆ …   ticker 52px, inverted │
└────────────────────────────────────────────────────┘
  chip: position fixed, follows pointer, z-index 5
  • .top — 4-column grid, aria-label="Studio details". First line of each cell is <b>.
  • <main class="stage"> — flex column, vertically centred. .kick then <button class="mail">.
  • .mail — all:unset; contains visible .t (aria-hidden) and .sr “Copy email address hi@ferro.work”. aria-describedby="hint".
  • #hint sr: “Copies the address to your clipboard”. #live sr aria-live="assertive".
  • <section class="grid" aria-label="Other contacts"> — four cells. Copyable items are <a href="#" data-copy="…">.
  • .tick — aria-hidden, inner flex row duplicated so the 38s loop is gapless. Each item has a 14px diamond ::after (rotated 45° square).
  • .chip — aria-hidden, not in the tab order.

Tokens

:root {
  /* colour — safety-orange field, near-black ink, cream flash */
  --bg: #ff4f1a;          /* page */
  --ink: #0d0d0d;         /* type, rules, ticker, chip */
  --paper: #f2efe6;       /* flash type, copied address */
  --line: rgba(13, 13, 13, .9);  /* 2px rules */
  --ink-2: #3a1a0e;       /* declared; body colour is --ink */

  /* type */
  --display: "Anton", Impact, sans-serif;
  --mono: "Space Mono", ui-monospace, monospace;

  /* layout */
  --pad: 40px;
  --rule: 2px;
  --mail-fs: 200px;       /* base; JS may raise to 260px cap */
  --tick-h: 52px;

  /* motion */
  --t-micro: 140ms;
  --t-wipe: 420ms;
  --t-scramble-out: 720ms;
  --t-hold: 1600ms;
  --t-scramble-in: 640ms;
  --ease: cubic-bezier(.2, .7, .2, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --roll: 38s;
}

Typography

RoleFamilySizeWeightLine-heightTrackingCase
Address / copiedAnton200px (fit)4000.86−0.01emUPPERCASE
TickerAnton28px4001+0.02emUPPERCASE
Body / metaSpace Mono13px4001.50sentence
Top labelsSpace Mono13px400/7001.5+0.04emUPPERCASE
KickSpace Mono13px700/4001.5+0.04emUPPERCASE
Grid headingsSpace Mono12px7001+0.06emUPPERCASE
ChipSpace Mono12px7001+0.06emUPPERCASE
Grid linksSpace Mono13px4001.50as written

Kick right label is weight 400; left is 700. Top cells: <b> 700, second line 400.

Motion

ElementTriggerPropertyFrom → ToDurationEasingNotes
Address underlinehover / focustransform scaleX0 → 1420ms--ease-outorigin left; 14px tall at bottom 6px
Chippointermoveopacity, transform0, scale .6 → 1, translate(14,14)140ms / 200ms--ease / --ease-outleft/top = clientX/Y
Body flashcopy successbackground, colororange/ink ↔ ink/paper140ms--easealso invert rule colours
Glyph scramblecopy / reverttextContent per charrandom glyphs → target720ms / 640ms—refresh ≥48ms; see notes
Link hoverhoverbackground, colorinherit → ink on --bginstant—flash invert: paper on ink
Tickerload, looptranslateX0 → −50%38slinearinfinite; content duplicated
Link labeldata-copy clicktextContentoriginal → Copied → original1400ms—

Scramble: for target string of length n and duration dur, char i locks at at[i] = (i/n)*dur*0.7 + random()*dur*0.3. Before at[i]*0.4 show the previous character if it exists; otherwise pick from #%&*+=/\\<>[]{}?!0123456789ABCDEFGHJKLMNPQRSTUVWXYZ. Spaces lock immediately. Reduced motion: set textContent to the target and skip the loop.

States

  • Default: orange page, black type, chip opacity 0, underline scaleX(0).
  • Address hover: chip .on, underline full, cursor: none.
  • Address focus-visible: 3px ink outline, 6px offset; underline also wipes in.
  • Copied / flash: page black, type cream, rules cream, ticker orange with black diamonds. Chip: background --paper, colour --ink. Address colour --paper.
  • Busy: a second click during the 1600ms hold clears the timeout and runs copy again; busy stays true until the return scramble finishes.
  • Copy failed: live region “Copy failed. The address is hi@ferro.work”; scramble target stays HI@FERRO.WORK (do not show COPIED TO CLIPBOARD).
  • Grid link copied: text “Copied” or “Copy failed” for 1400ms.
  • Grid link hover: background --ink, colour --bg; 2px underline is border-bottom: 2px solid currentColor.
  • No hover (touch): .mail { cursor: pointer }, chip display: none.

Accessibility

  • Address is a real <button type="button">. Visible Anton span is aria-hidden; an .sr child names the action. aria-describedby points at the hint.
  • Live region is aria-live="assertive" and visually clipped (1×1).
  • Grid copy controls are links with href="#"; preventDefault on click. Studio block has no copy action.
  • Keyboard: Tab hits the address button then the three copy links. Enter/Space activates copy (native button). Focus ring 3px on the address, 2px on grid links.
  • Chip is pointer-only decoration (aria-hidden, pointer-events: none).
  • Contrast: black on #FF4F1A is well above 4.5:1 for 13px mono; cream on black during flash likewise. Anton at 200px is display type.
  • Hit target: the address button includes 14px + 26px vertical padding; grid links are inline but sit in padded cells.

Responsive rules

  • ≥ 1280: as specified. Address fits via the probe; do not wrap.
  • 1024–1279: keep four columns; the probe will drop the Anton size below 200px as needed (floor is whatever min(260, 200 * width / probe) yields).
  • 768–1023: top and grid become 2×2; ticker still 52px. Address white-space: nowrap remains — shrink the font, never wrap.
  • < 640: single column meta; --pad: 20px. Hide the ticker or let it clip. Chip already hidden on coarse pointers.
  • Reduced motion as above. Do not disable copy.

Acceptance checklist

  • Display string is HI@FERRO.WORK in Anton, one line, fitted so it never overflows the content width.
  • Click copies hi@ferro.work (lowercase) and announces success or the spoken fallback address.
  • Successful copy flashes the page to black/cream and scrambles to COPIED TO CLIPBOARD in 720ms, holds 1600ms, scrambles back in 640ms.
  • Hovering the address hides the system cursor and shows a “Copy ↗” pill that tracks the pointer.
  • A 14px underline wipes in over 420ms with cubic-bezier(.16,1,.3,1).
  • Phone, press@ and jobs@ each copy their data-copy value and briefly read “Copied”.
  • Lisbon clock uses Europe/Lisbon and updates at least every 30s.
  • Ticker loops in 38s; content is duplicated so the join is invisible.
  • Reduced motion skips scramble frames and the ticker animation; copy still works.
  • Focus-visible rings are present on the address and every copy link.
  • On touch (hover: none) the address uses cursor: pointer and the chip is not shown.
  • Rules are 2px and invert with the flash.

Implementation notes

Fit the string with a hidden probe cloned from .t, 200px, off-canvas. Measure after fonts.ready and on resize:

function sizeFor(str) {
  probe.textContent = str;
  const w = probe.getBoundingClientRect().width || 1;
  return Math.min(260, 200 * (mail.clientWidth / w));
}
t.style.fontSize = sizeFor(str).toFixed(1) + 'px';

Clipboard with fallback (the iframe sandbox may lack clipboard permission):

async function copyText(s) {
  try { await navigator.clipboard.writeText(s); return true; }
  catch {
    const a = document.createElement('textarea');
    a.value = s; a.style.cssText = 'position:fixed;opacity:0';
    document.body.appendChild(a); a.select();
    const ok = document.execCommand('copy'); a.remove(); return ok;
  }
}

Scramble lock times — later characters stay noisy longer; cap glyph refresh at 48ms so it does not look like a flicker storm:

const at = [...to].map((_, i) => (i / n) * dur * .7 + Math.random() * dur * .3);
// each frame: (e >= at[i] || c === ' ') ? c : (e < at[i]*.4 && from[i] ? from[i] : GLYPHS[rnd])

Common mistakes: copying the display string HI@FERRO.WORK instead of lowercase; wrapping the Anton line; using cursor: none on body (only the address); driving the ticker with JS instead of a 38s CSS loop; forgetting all:unset on the button so a native border shows; putting the live region in a polite status that is skipped during the scramble.

Details

Palette
Type
Anton · Space Mono
Motion
Rich motion
Build
One session
Designed bySusan AcharyaKathmandu

Studied

Don't Board Me

A service with a next step. The headline can shout. The booking stays plain.

All sources