Havjoy Design System
v1.0 · Internal reference · ↓ Table of contents
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
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)
Card Title
Supporting text
.hj__card.hj__card--lg
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)
1:1 (square)
4:3 (landscape)
16:9 (wide)
5. Badges & Pills
Eyebrow pills, category badges, counters.
Eyebrow Pills (.hj__pill)
<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)
<span class="hj__badge-category">ANNIVERSARY</span>
Counter / Accent Badges
Stars (.hj__stars)
<span class="hj__stars">★★★★★</span>
6. Banners
Full-width announcement strips.
.hj__banner--ink
<div class="hj__banner hj__banner--ink">...</div>
.hj__banner--pink
.hj__banner--yellow
7. Form Elements
Quantity stepper and variant selectors.
Quantity Stepper (.hj__quantity)
<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
.hj__grid-2
.hj__grid-3
Horizontal scroll (.hj__hscroll)
<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.
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
Eyebrow pills, floating badges
<span class="hj__pill hj__anim-float">
.hj__anim-heartbeat
Urgency markers, discount badges
<span class="hj__pill hj__pill--pink hj__anim-heartbeat">
.hj__anim-tilt
Hand-stamped organic feel tags
<span class="hj__pill hj__pill--yellow hj__anim-tilt">
.hj__anim-stamp-in
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
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)
JS-driven via IntersectionObserver. Runs once on scroll-in.
<span class="hj__anim-countup" data-count-to="200+">0</span>
.hj__anim-pop
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)
Section reveal. Starts opacity:0. JS adds .is-visible when 15% visible.
<div class="hj__anim-fadeup">...</div>
.hj__anim-slide-left (JS)
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
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
.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
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>
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
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 |
<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
Crafted in Kentucky.
Real artists in our Louisville studio.
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.
badge_text, headline_prefix, headline_accent, sub_text, step1_label, step1_date, step2_label, step2_date, step3_label, arrive_days, arrives_textAnimations: live-pulse (green dot) · line-progress (gradient fill) · dot1/2/3-fill (step circles) — all use
prefers-reduced-motion fallback.