Design Lounge
Install

Nº 121 of 520

Logos mono marquee

A quiet two-row Tally customer marquee: monochrome type wordmarks, 42s/54s linear scroll, pause on hover, static under reduced motion.

Preview

Open full size
1280 × 800 · 7.3 KB · 137 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 "Logos mono marquee" (piece logos-mono-marquee) 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

181 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 logos section for Tally, a payroll product. Two 96px rows of monochrome wordmarks — names set in Schibsted Grotesk or IBM Plex Mono, some with a 14px geometric prefix (square, circle, bars, plus) built from CSS, never from image files. Row A scrolls left in 42s; row B scrolls right in 54s. Hover or focus a row pauses that row only. Under prefers-reduced-motion: reduce both tracks are static and the duplicate set is hidden. This is a quiet swiss strip, not a kinetic type specimen: 18px marks on #F4F4F0, hairlines, no colour logos.

Reference behaviour

  1. Initial state: 56px nav (7px square + Tally + Payroll / Tax / Pricing in mono + “Open a book”). Lead: kicker “USED IN 48 PAYROLLS”, 40px heading “Teams that run the book on Tally”, right meta “Two rows / Monochrome type / Hover a row to pause”. Two hairline-boxed rows already moving. Footer hint names the 42 s / 54 s clocks.
  2. Hover row A: animation-play-state: paused on that track only. Row B keeps moving.
  3. Hover row B: same, only B pauses.
  4. Keyboard-focus a row (tabindex="0"): same pause via :focus-within.
  5. Leave the row: that track resumes from the same offset (CSS animation, not a JS restart).
  6. Hover “Open a book”: invert to #111 fill, #F4F4F0 text.
  7. Reduced motion: both animations none, transform none, the cloned .set is display:none. Eight wordmarks per row sit in document flow and may clip at the right edge — do not wrap them onto a second line inside the row.

Structure

1280 × 800
┌──────────────────────────────────────────────────────────────────────┐
│ ■ Tally      Payroll   Tax   Pricing                  Open a book    │ 56
│                                                                      │
│ USED IN 48 PAYROLLS                    Two rows                      │
│ Teams that run the book                Monochrome type               │
│ on Tally                               Hover a row to pause          │ 48+36
│──────────────────────────────────────────────────────────────────────│
│ ■ Northline │ HARBOR & CO │ ○ VALE CIVIC │ ≡ Kiln Studio │ … →      │ 96
│──────────────────────────────────────────────────────────────────────│
│ ← WESTBOUND │ ○ Ledger & Son │ ≡ MOTH HOUSE │ Brine │ …             │ 96
│──────────────────────────────────────────────────────────────────────│
│ Wordmarks set in type · no image files     42 s / 54 s · linear · …  │ 20+
└──────────────────────────────────────────────────────────────────────┘
  pad 64
  • <nav> 56px: .brand, three mono .links a, .cta.
  • <section aria-label="Customer wordmarks">: .lead, .rows, .hint.
  • Each .row contains .track > two .sets. The second set is a clone (aria-hidden="true") so translateX(-50%) loops.
  • Each .logo is a <span>: optional .ico + .w word. Variants: default 18px Grotesk, .caps 13px/600 +0.18em uppercase Grotesk, .mono 13px/500 +0.08em uppercase Plex Mono.
  • Icon classes: .sq filled 14px square, .ci 1.5px ring, .bars two 2px rules, .plus 2px cross.

Row A names, in order: Northline (sq), Harbor & Co (caps), Vale Civic (mono + ci), Kiln Studio (bars), Orchard (caps + plus), Pine Desk, Atlas Yard (mono), Copper Mill (sq).

Row B names, in order: Westbound (caps), Ledger & Son (ci), Moth House (mono + bars), Brine, Oak & Hour (caps + plus), Second Shift, Quarry (mono + sq), Redoubt.

Do not use real brand names. Do not draw SVG logos.

Tokens

:root {
  --bg: #f4f4f0;          /* page */
  --ink: #111111;         /* type, CTA, focus, brand square */
  --ink-2: #6e6e6a;       /* kicker, links, meta */
  --ink-3: #9a9a94;       /* hint */
  --line: #d8d8d2;        /* hairlines */
  --mark: #3a3a38;        /* wordmarks + icons */

  --sans: "Schibsted Grotesk", system-ui, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, monospace;

  --nav-h: 56px;
  --row-h: 96px;
  --pad: 64px;
  --logo-pad-x: 36px;
  --ico: 14px;

  --t-fast: 160ms;
  --ease: cubic-bezier(.2, .7, .2, 1);
  --dur-a: 42s;
  --dur-b: 54s;
}

Typography

RoleFamilySizeWeightLine-heightTrackingCase
BodySchibsted Grotesk14px4001.450sentence
BrandSchibsted Grotesk15px6001−0.03emsentence
Nav linksIBM Plex Mono12px40010sentence
CTAIBM Plex Mono11px5001+0.06emUPPERCASE
Kicker / hintIBM Plex Mono11px4001–1.4+0.14em / +0.04emUPPERCASE
HeadingSchibsted Grotesk40px6001.1−0.03emsentence
MetaIBM Plex Mono12px400 / 5001.50sentence
Wordmark defaultSchibsted Grotesk18px5001−0.02emsentence
Wordmark capsSchibsted Grotesk13px6001+0.18emUPPERCASE
Wordmark monoIBM Plex Mono13px5001+0.08emUPPERCASE

Heading measure is max-width: 16ch so it breaks onto two lines at 1280.

Motion

ElementTriggerPropertyFrom → ToDurationEasingNotes
.row.a .trackloadtranslateX0 → −50%42slinearinfinite
.row.b .trackloadtranslateX−50% → 054slinearinfinite, opposite
.trackrow hover / focus-withinanimation-play-staterunning → paused0—that row only

Reduced motion:

@media (prefers-reduced-motion: reduce) {
  .row.a .track, .row.b .track { animation: none; transform: none; }
  .set:last-child { display: none; }
}

No easing on the scroll. No speed-up. No colour pulse.

States

  • Row rest: scrolling.
  • Row hover / focus-within: that track paused. 2px #111 focus ring, 3px offset, on the row box.
  • CTA rest: 32px, 1px #111 border, transparent fill, 11px mono uppercase.
  • CTA hover: inverted.
  • Link hover: colour #111.
  • Wordmarks do not have their own hover colour. They stay --mark #3A3A38.

Accessibility

  • Section: aria-label="Customer wordmarks".
  • Each row is focusable with an aria-label that names the direction (“Customer row one, scrolling left” / “row two, scrolling right”).
  • The cloned set is aria-hidden="true" so names are not read twice.
  • Icons are aria-hidden="true"; the name in .w is the accessible text.
  • Keyboard: Tab through brand → links → CTA → row A → row B. Focusing a row pauses it.
  • Contrast: #111 on #F4F4F0 is 17:1; #3A3A38 on #F4F4F0 is ~11:1; #6E6E6A on #F4F4F0 is 5.1:1.
  • Hit targets: rows are 96px tall; CTA 32px with 12px padding. The pause target is the whole row, not a single wordmark.

Responsive rules

  • ≥ 1280: pad 64px, heading 40px, logo padding 36px, both rows moving.
  • 1024–1279: pad 36px, heading 32px. Speeds unchanged.
  • 768–1023: nav links hide, heading 28px, logo padding 22px. Rows still 96px.
  • < 640: heading 24px. Keep two rows; do not stack the marquees. Reduced-motion static row may clip — that is acceptable.

Acceptance checklist

  • First frame shows the 40px heading and two 96px hairline rows of monochrome type already in motion.
  • No <img>, no inline SVG wordmarks — names are type, icons are 14px CSS geometry.
  • Row A duration is 42s left; row B duration is 54s right; both linear and infinite.
  • Hovering or focusing a row pauses only that row; the other continues.
  • Duplicate set is aria-hidden and the loop is translateX(-50%).
  • prefers-reduced-motion: reduce stops both tracks and hides the clones.
  • Sixteen fictional names as specified; no real brands.
  • CTA inverts on hover; focus rings are 2px #111, 3px offset.
  • Palette stays near-white / black / grey — no accent colour on the marks.
  • Demo fills 1280×800, starts with the piece header comment, and uses only Schibsted Grotesk + IBM Plex Mono.

Implementation notes

Closed loop. Duplicate the set so the track is two identical halves, then travel exactly 50%:

.track { display: flex; width: max-content; }
.row.a .track { animation: marq 42s linear infinite; }
@keyframes marq { from { transform: translateX(0); } to { transform: translateX(-50%); } }

Clone in JS on load so the markup lists each name once. Use nextElementSibling, not [aria-hidden="true"] — the 14px icons also have that attribute and would swallow the clone:

['set-a', 'set-b'].forEach((id) => {
  const src = document.getElementById(id);
  src.nextElementSibling.innerHTML = src.innerHTML;
});

Pause without restarting. Do not remove the animation class. Use animation-play-state: paused on :hover and :focus-within of the row.

Common mistakes: colour logos or favicon PNGs; a single row; ease instead of linear (the seam jumps); restarting animation on mouseleave so the row snaps; giant kinetic type (that is a different piece); forgetting to hide the clone under reduced motion, which would show every name twice, static.

Details

Palette
Type
Schibsted Grotesk · IBM Plex Mono
Motion
Subtle motion
Build
One session
Designed bySusan AcharyaKathmandu

Studied

Moremedia

Set the services as tall labels. Open one, and keep the rest as type.

All sources