Havjoy Design System

v1.0 · Internal reference · ↓ Table of contents

INTERNAL

Table of Contents


1. CSS Tokens

Defined on :root. Available on every page since CSS loads globally.

Brand Colors

--hj-ink #010101
--hj-cream-2 #fffcf3
--hj-yellow #fdcd62
--hj-pink #fb5780
--hj-blue #c5d8e8

Text Colors

--hj-text-muted Muted text (55% opacity)
--hj-text-subtle Subtle text (40% opacity)
--hj-text-faint Faint text (25% opacity)

Shadows

--hj-shadow-card Shadow Card (4px)
--hj-shadow-card-lg Shadow Card LG (6px)
--hj-shadow-pill Shadow Pill (2px)
--hj-shadow-pill-sm Shadow Pill SM (1.5px)

Spacing Scale

--hj-space-1
4px
--hj-space-2
8px
--hj-space-3
12px
--hj-space-4
16px
--hj-space-5
20px
--hj-space-6
24px
--hj-space-7
28px
--hj-space-8
32px

2. Typography Utilities

Không set font-size global — dùng theme defaults hoặc set inline. Chỉ apply Playfair cho display headings.

.hj__display

The canvas they'll never take down.

<h2 class="hj__display" style="font-size: 36px;">...</h2>

.hj__display-italic

Made with love.

<em class="hj__display-italic" style="font-size: 36px;">...</em>

.hj__text-eyebrow

WHY CUSTOMERS HESITATE

<p class="hj__text-eyebrow" style="font-size: 11px;">...</p>

Text helpers

.hj__text-muted — Secondary descriptions, subtitles .hj__text-subtle — Captions, meta labels .hj__text-faint — Placeholder, hints .hj__text-pink — Accent, italic highlight

3. Buttons

Base class .hj__button + variant modifier.

.hj__button--primary

<button class="hj__button hj__button--primary">Primary (Yellow) →</button>

.hj__button--secondary

<button class="hj__button hj__button--secondary">Secondary (White) →</button>

.hj__button--inverse

<button class="hj__button hj__button--inverse">Inverse (Ink) →</button>

.hj__button--pink

<button class="hj__button hj__button--pink">Pink →</button>

.hj__button--full

<button class="hj__button hj__button--primary hj__button--full">Full Width →</button>

4. Cards

Base class .hj__card + optional modifiers.

.hj__card (default)

4:5 image

Card Title

Supporting text

.hj__card.hj__card--lg

4:5 image

Large Card

Heavier border + shadow

.hj__card.hj__card--ghost

Ghost Card

Transparent, subtle border

.hj__card.hj__card--ink

Ink Card

Dark background variant

On dark background — coloured border & shadow

.hj__card--shadow-yellow

Yellow shadow

Black border, yellow shadow

.hj__card--shadow-pink

Pink shadow

Black border, pink shadow

.hj__card--on-ink-yellow

Ink yellow

Yellow border + shadow

.hj__card--on-ink-pink

Ink pink

Pink border + shadow

Image aspect ratios

4:5 (default portrait)
4:5 (default portrait)
1:1 (square)
1:1 (square)
4:3 (landscape)
4:3 (landscape)
16:9 (wide)
16:9 (wide)

5. Badges & Pills

Eyebrow pills, category badges, counters.

Eyebrow Pills (.hj__pill)

● WHY IT WORKS ● OUR STUDIO ● LIMITED OFFER ● NEW ARRIVAL
<span class="hj__pill" style="font-size: 11px;">● LABEL</span>
<span class="hj__pill hj__pill--ink" style="font-size: 11px;">● LABEL</span>

Category Badges (.hj__badge-category)

ANNIVERSARY COUPLES DARK BG
<span class="hj__badge-category">ANNIVERSARY</span>

Counter / Accent Badges

2 / 5 SELECTED ⭐ #1 Bestseller

Stars (.hj__stars)

★★★★★ 4.9 from 1,124 reviews
<span class="hj__stars">★★★★★</span>

6. Banners

Full-width announcement strips.

.hj__banner--ink

● $10 OFF · CODE RETARGET10  ·  ● FREE PREVIEW · NO PAYMENT UNTIL APPROVED
<div class="hj__banner hj__banner--ink">...</div>

.hj__banner--pink

Mother's Day · Order by May 4 for guaranteed delivery

.hj__banner--yellow

Flash Sale · 20% off all canvas prints today only

7. Form Elements

Quantity stepper and variant selectors.

Quantity Stepper (.hj__quantity)

1
<div class="hj__quantity">
  <button class="hj__quantity-btn">−</button>
  <span class="hj__quantity-value">1</span>
  <button class="hj__quantity-btn">+</button>
</div>

Variant Grid (.hj__variant-grid)

<div class="hj__variant-grid hj__variant-grid--3">
  <button class="hj__variant hj__variant--active">9×12</button>
  <button class="hj__variant">12×16</button>
</div>

8. Layout Utilities

Section wrappers, containers, grids, stacks.

Section themes

.hj__section--cream
.hj__section--ink
.hj__section--pink
.hj__section--yellow

Grid utilities

Col 1
Col 2
.hj__grid-2
1
2
3
.hj__grid-3

Horizontal scroll (.hj__hscroll)

1
2
3
4
5
6
7
8
<div class="hj__hscroll">
  <div class="hj__hscroll-item">...</div>
</div>

9. Animation Library

17 utility classes. Prefix .hj__anim-* — tất cả respect prefers-reduced-motion.

Performance rule: chỉ animate transform + opacity. KHÔNG animate width/height/top/left.

1 · Button Animations

.hj__anim-press

Primary CTA idle hint

<button class="hj__button hj__button--primary hj__anim-press">

.hj__anim-wiggle

Secondary CTA attention grab (4s cycle)

<button class="hj__button hj__anim-wiggle">

.hj__anim-shine

Premium sweep — hero CTA

<button class="hj__button hj__button--primary hj__anim-shine">

.hj__anim-pulse-glow

Pink ripple — discount / urgency CTA

<button class="hj__button hj__anim-pulse-glow">

2 · Pill / Badge Animations

.hj__anim-float

★ NEW DROP ★

Eyebrow pills, floating badges

<span class="hj__pill hj__anim-float">

.hj__anim-heartbeat

🔥 HOT DEAL

Urgency markers, discount badges

<span class="hj__pill hj__pill--pink hj__anim-heartbeat">

.hj__anim-tilt

BESTSELLER

Hand-stamped organic feel tags

<span class="hj__pill hj__pill--yellow hj__anim-tilt">

.hj__anim-stamp-in

MADE IN USA

One-shot stamp entrance on page load

<div class="hj__anim-stamp-in">MADE IN USA</div>

3 · Background Animations

.hj__anim-twinkle → .hj__twinkle-dot

Section atmosphere dots. Parent gets .hj__anim-twinkle, SVG circles get .hj__twinkle-dot.

<svg class="..."><circle class="hj__twinkle-dot" .../></svg> (wrap parent in .hj__anim-twinkle)

.hj__anim-drift

&

Giant decorative shapes (ampersand, star). Set --hj-rotate to initial angle.

<svg class="hj__anim-drift" style="--hj-rotate:-12deg;">

.hj__anim-marquee / .hj__anim-marquee-content

★ $10 OFF ★ FREE SHIP $80+ ★ MADE IN KENTUCKY ★ $10 OFF ★ FREE SHIP $80+ ★ MADE IN KENTUCKY

Promo banner. Duplicate content 2× for seamless loop.

<div class="hj__anim-marquee"><div class="hj__anim-marquee-content"><span>...</span><span>...</span></div></div>

4 · Number Animations

.hj__anim-countup + data-count-to (JS)

0
Canvases/day
0
Inspected
0
Reviews

JS-driven via IntersectionObserver. Runs once on scroll-in.

<span class="hj__anim-countup" data-count-to="200+">0</span>

.hj__anim-pop

200+
100%
4–5

Pop entrance. Stagger with inline animation-delay.

<div class="hj__anim-pop" style="animation-delay:0.15s">

5 · Entrance Animations (scroll-triggered)

.hj__anim-fadeup (JS)

↑ Fades up on scroll

Section reveal. Starts opacity:0. JS adds .is-visible when 15% visible.

<div class="hj__anim-fadeup">...</div>

.hj__anim-slide-left (JS)

Step 1
Step 2
Step 3

List stagger. Add animation-delay inline.

<div class="hj__anim-slide-left" style="animation-delay:0.15s">

.hj__anim-bounce-in

Modals, success states, checkmarks. No JS needed.

<div class="hj__anim-bounce-in">✓</div>

6 · Special

.hj__anim-confetti

🎉 Order placed!

Celebration rain. 8–12 particles, staggered via nth-child. Wrap in position:relative;overflow:hidden.

<div class="hj__anim-confetti" style="position:absolute;top:0;left:20%;width:8px;height:8px;background:var(--hj-yellow);"></div>

Legacy animations (unchanged)

.hj__twinkle-dot
.hj__pulse
Fade up
.hj__fade-up

11. Comparison Slider

Drag-to-compare before/after component. No external library — vanilla JS + CSS clip-path. Requires couple-collection.css + couple-collection.js.

Live demo — drag the handle

Digital preview
WHAT YOU SEE
Canvas delivered
WHAT YOU GET

Class reference

Class Role
.hj__cc-compare [data-compare] Wrapper — aspect-ratio + overflow:hidden + cursor ew-resize
.hj__cc-compare-img Abs-positioned image layer (inset:0 covers full wrapper)
.hj__cc-compare-img--before z-index:1 — base layer
.hj__cc-compare-img--after z-index:2 — top layer clipped by JS via clip-path inset() (delivered / LEFT side)
.hj__cc-compare-handle Drag handle — line + circle button at z-index:4
.hj__cc-compare-line 2px black vertical divider with white halo shadow
.hj__cc-compare-btn Circle button with ←→ arrows
.hj__cc-pvd-label Pill label — lives INSIDE its image layer so it clips with it
.hj__cc-pvd-label--preview Yellow pill: WHAT YOU SEE — inside --before at right:12px
.hj__cc-pvd-label--delivered Ink pill: WHAT YOU GET — inside --after at left:12px

HTML

<div class="hj__cc-compare" data-compare>
  <!-- --before: base layer, always visible — preview image, RIGHT side -->
  <div class="hj__cc-compare-img hj__cc-compare-img--before">
    <img src="preview.jpg" alt="Digital preview" loading="lazy">
    <span class="hj__cc-pvd-label hj__cc-pvd-label--preview">WHAT YOU SEE</span>
  </div>
  <!-- --after: top layer, clipped by JS — delivered image, LEFT side -->
  <div class="hj__cc-compare-img hj__cc-compare-img--after">
    <img src="delivered.jpg" alt="Canvas delivered" loading="lazy">
    <span class="hj__cc-pvd-label hj__cc-pvd-label--delivered">WHAT YOU GET</span>
  </div>
  <div class="hj__cc-compare-handle" aria-hidden="true">
    <div class="hj__cc-compare-line"></div>
    <div class="hj__cc-compare-btn"> <!-- ←→ SVG --> </div>
  </div>
</div>
How it works: The --after (delivered) layer starts at clip-path: inset(0 50% 0 0) — showing only the LEFT half. Dragging sets inset(0 (100−pct)% 0 0), expanding left. The handle mirrors via left: pct%. Labels live inside their own image layer so they clip naturally with it — the yellow "WHAT YOU SEE" pill hides as you drag right, the ink "WHAT YOU GET" pill hides as you drag left. setPointerCapture keeps drag active if the cursor moves outside the wrapper quickly.

10. Legacy Reference

⚠ Page mới CHỈ dùng .hj__* — KHÔNG copy legacy classes vào page mới

So sánh legacy classes của 3 page cũ với shared equivalent. Legacy vẫn hoạt động bình thường — không bị touch.

Legacy class Page Shared equivalent Note
.hj-rtg__btn--xl retarget .hj__button--primary .hj-rtg__btn--xl has 5px shadow (heavier)
.hj-md__hero-cta mothers-day .hj__button--primary Identical styling
.hj-rtg__eyebrow retarget .hj__pill + .hj__text-eyebrow Legacy combines pill + text
.hj-rtg__obj-card retarget .hj__card Legacy has no box-shadow
.hj-rtg__rvs-card retarget .hj__card Same base structure
.hj-rtg__studio-stat retarget .hj__card--cream Dark background differs
.hj-myart__main-image my-artwork .hj__card-image 4:5 aspect ratio same
.hj-rtg__ann retarget .hj__banner--ink Legacy is marquee (animated)

12. Halftone Backgrounds

8 patterns — pure CSS radial-gradient + mask. No SVG, no DOM nodes. Content inside must have position:relative; z-index:1.

1 · Corner Fade — top-right spotlight

hj__bg-corner-light

Section heading

Supporting text

<section class="hj__bg-corner-light"><div style="position:relative;z-index:1">...</div></section>

Spotlight effect, dramatic hero — light theme

hj__bg-corner-dark

Section heading

Supporting text

<section class="hj__bg-corner-dark">

Comic panel, How It Works — dark theme · dots yellow 85%

2 · Diagonal — 2 strips −12° · top-right + bottom-left

hj__bg-diagonal-light

Section heading

Dynamic feel, tilted pattern

<section class="hj__bg-diagonal-light">

Dynamic panel — light · ::before top-right + ::after bottom-left · center clear

hj__bg-diagonal-dark ⭐

Section heading

Dynamic feel, tilted pattern

<section class="hj__bg-diagonal-dark">

Dynamic panel — dark · dots pink 100% / 1.7px (extra visible)

3 · Split Corners — 2-accent (35% × 35%), mask fade 80%

hj__bg-split-light

Section heading

Pink top-right · Black bottom-left

<section class="hj__bg-split-light">

Final CTA light · asymmetric balance · uses ::before + ::after

hj__bg-split-dark

Section heading

Yellow top-right · Pink bottom-left

<section class="hj__bg-split-dark">

Final CTA dark · uses ::before + ::after — cannot combine with other pseudo-element classes

4 · Pan ⚙️ — top + bottom strips, opposite direction (12s)

hj__bg-pan-light

Section heading

Top + bottom strips pan opposite

<section class="hj__bg-pan-light">

Order timing, How It Works — light · respects prefers-reduced-motion

hj__bg-pan-dark

Section heading

Top + bottom strips pan opposite

<section class="hj__bg-pan-dark">

Dark sections — dots yellow 60% · ::before top + ::after bottom reverse

Class Theme Dot color Density Animated
.hj__bg-corner-light Light black 45% / 1.5px 9px
.hj__bg-corner-dark Dark yellow 85% / 1.5px 9px
.hj__bg-diagonal-light Light black 40% / 1.5px 9px
.hj__bg-diagonal-dark ⭐ Dark pink 100% / 1.7px 9px
.hj__bg-split-light Light pink 45% + black 40% / 1.5px 9px
.hj__bg-split-dark Dark yellow 85% + pink 70% / 1.5px 9px
.hj__bg-pan-light ⚙️ Light black 40% / 1.5px 14px 12s top+bottom
.hj__bg-pan-dark ⚙️ Dark yellow 60% / 1.5px 14px 12s top+bottom
⚠️ Split + Diagonal + Pan use both ::before and ::after — cannot be combined with other classes that also use pseudo-elements. All patterns: wrap your content in <div style="position:relative;z-index:1"> so it sits above the pattern (or rely on the auto-lift rule: direct children of .hj__bg-* get this automatically).

13. Order Timeline

Trust section — 3-step shipping timeline with animated progress bar. Used on retarget page + couple-collection. Section file: sections/order-timeline.liquid

Live Demo

HAVJOY STUDIO · SINCE 2019

Crafted in Kentucky.

Real artists in our Louisville studio.

YOU ORDER
Today
WE SHIP
Tomorrow
YOU GET IT
Arrives in 3–5 business days

Usage

{% section 'order-timeline' %}

All text configurable via Shopify theme editor. arrive_days (number) calculates the delivery date dynamically via hj-timeline.js. Animation keyframes defined in hj-design-system.css.

Schema fields: badge_text, headline_prefix, headline_accent, sub_text, step1_label, step1_date, step2_label, step2_date, step3_label, arrive_days, arrives_text
Animations: live-pulse (green dot) · line-progress (gradient fill) · dot1/2/3-fill (step circles) — all use prefers-reduced-motion fallback.