Retail Circle

DesignSystem_StyleGuide

The single source of truth for the Retail Circle look. Every colour, size, and component below is driven by src/styles/tokens.css. This page is the contract — build from these tokens and components, and the whole site stays consistent. Change a token in that file and everything here (and everywhere it's used) updates at once.

How to use this system

  1. Import the tokens once, before any other CSS:import '../styles/tokens.css' (already wired in BaseLayout.astro).
  2. Only use public --rc-* tokens — never a raw hex, and never a private --_rc-* primitive (those exist only to build the gradients).
  3. Reach for a component before writing markup. Button, Card, Input, Link, and Badge live in src/components/ — use them instead of bespoke HTML.
  4. Pick tokens by role, not by number — --rc-text-h2, not "36px";--rc-surface, not "that grey".
  5. One primary action per view. Everything else is secondary / ghost.
  6. Check the contrast matrix before putting a colour on a surface.

Colours — Brand

Four direct-use brand colours. Choosing: CTA / accent → --rc-purple; eyebrow / link / accent-on-dark → --rc-lilac. Never use purple for body-size text on the page bg (fails contrast).

--rc-purple#694ef7Primary CTA / accent
--rc-purple-deep#5038d3Hover / pressed
--rc-lilac#cdaafbEyebrow / link / on-dark accent
--rc-lilac-mid#9777f4Mid lilac accent

Colours — Gradient internals

These only feed the gradients below. Do not use them directlyin components — pick a Brand colour or a gradient token instead.

--_rc-purple-vivid#7a11ffVivid gradient stop
--_rc-blue-purple#636affGradient tail
--_rc-lilac-pale#e2b8faGradient start

Colours — Neutrals (semantic roles)

The only neutral tokens to use. Pick by role — --rc-text /--rc-text-muted for copy, --rc-bg →--rc-surface → --rc-surface-raised for elevation. The raw grey ramp is private (--_rc-neutral-*) — never consume it.

--rc-text#ffffffPrimary text on dark
--rc-text-muted#c3c3d0Secondary text
--rc-text-subtle#8f8fa5Placeholder / subtle
--rc-border#484853Default hairline
--rc-border-soft#333336Faint divider
--rc-bg#1c1c1fPage background
--rc-surface#333336Raised card / panel
--rc-surface-raised#3d3d42Higher card / modal

Colours — System

--rc-danger#ff5a65Error / destructive
--rc-success#35c66bSaved / valid
--rc-warning#f5a623Caution / pending
--rc-link#cdaafbInline body-copy link
--rc-focus-ring#cdaafbKeyboard focus outline

Contrast matrix

Computed live from the token hexes (WCAG 2.1). AA = safe for body text, AA large = only 18px+/bold, FAIL = don't use for text. Note --rc-purple is AA-large only — fine for headings and big CTAs, never for body copy.

text / accent--rc-bg--rc-surface--rc-surface-raised
--rc-text17.0AAA12.6AAA10.8AAA
--rc-text-muted9.7AAA7.2AAA6.2AA
--rc-text-subtle5.4AA4.0AA large3.4AA large
--rc-lilac (link)8.7AAA6.4AA5.5AA
--rc-purple3.3AA large2.4FAIL2.1FAIL

Gradients

--rc-gradient-primarySignature CTA / pill
--rc-gradient-richHero words / large fills
--rc-gradient-barUnderlines / dividers / active tab
--rc-gradient-glassGlassmorphism card fill
--rc-gradient-scrimFade-to-bg scrim

Effects — mesh gradients, glow & grain

The modern ambient treatments: soft multi-blob mesh gradients, dramatic glows, and a subtle film grain overlay — all tuned to the RC palette. Use the <MeshBackground> and<Glow> components for section backdrops and heroes.

<MeshBackground> — grainy mesh gradient

variant="purple"
variant="ember"
variant="graphite"
grain={false}
<MeshBackground variant="purple" as="section">…hero content…</MeshBackground>

<Glow> — cinematic horizon (move your mouse over it)

Move your cursor left → right — the flare follows

Interactive by default: the anamorphic flare tracks the pointer along the seam, the arcs parallax, and it reveals on scroll-in. Rendering auto-pauses off-screen; parallax + tracking are disabled underprefers-reduced-motion. Pure CSS + a tiny vanilla script — no WebGL.

static (CSS)
image (PNG)
variant="spot"
<Glow variant="horizon" as="section">…hero…</Glow>          <!-- interactive by default -->
<Glow variant="horizon" interactive={false} />               <!-- static -->
<Glow variant="horizon" image />                             <!-- pixel-exact PNG -->

<ReededGlass> — fluted glass ridges

Vertical glass flutes that refract the light behind them (the "glass board" look). Built faithfully from the Figma technique: semi-transparent bars with a dark→clear fill, a real background-blur, and a bright inner-edge, over a colourful glow. variant="glow" is self-contained;variant="panel" overlays and refracts your own content.

✦ Retail Circle

Glass
Effect

Reeded glass reference
Reference target
Live <ReededGlass>
content behind the glass

Above: a panel laid over a gradient — the flutes bend and blur what's behind them. Tune flute width with width, coverage withband.

width="14px" (fine)
<ReededGlass variant="glow" band="52%" as="section">…hero title…</ReededGlass>
<ReededGlass variant="panel" />        <!-- overlay that refracts content behind it -->
<ReededGlass variant="glow" width="14px" />

<GlassPhoto> — reeded-glass photo overlay

A high-def image with a fluted-glass panel over part of it — the covered region is refracted through vertical glass ribs (real per-flute displacement) + softly blurred, while the rest stays sharp. The "Glass Texture / Glass Distortion" look. Set cover to place the glass, width / scale to tune the flutes & warp.

Portrait, sharp on the left with a reeded-glass overlay on the right
Houseplant photo seen through a centred reeded-glass band
<GlassPhoto src="/hero.jpg" alt="…" cover="right" />
<GlassPhoto src="/hero.jpg" alt="…" cover="center" width={20} scale={30} />
<GlassPhoto src="/hero.jpg" alt="…" cover="full" />

Underlying tokens

--rc-mesh-purple
--rc-mesh-ember
--rc-mesh-graphite
--rc-glow-horizon
--rc-glow-spot
--rc-grainoverlay only (mix-blend: overlay)

Reeded-glass reference board

The look we're matching: vertical fluted glass over a photo — the covered region is refracted through the ribs (one-sided dark→light degradé, soft dark-grey not black) and softly blurred, the rest stays crisp. Saved here so the effect can be recreated pixel-faithfully. Reproduce with<GlassPhoto> (photo overlay) or <ReededGlass>(glass over a glow).

Reeded Glass displacement system — poster, face refracted through vertical flutes
Displacement system — flutes over portrait
Reeded Glass system — tall board showing highlight & displacement maps
Highlight & displacement maps
Clarity — glass distortion over the right half of a face, sharp on the left
Half-covered — sharp vs. refracted
Blue reeded-glass texture swatch
Fluted-glass texture (blue)
Warm fluted degradé — amber & blue ribs on black
Warm degradé on black
Blue fluted degradé — soft dark-grey shadow between ribs
Blue degradé — soft dark-grey shadow

Typography

Heading face --rc-font-heading (Neue Haas Display Medium) · Body face --rc-font-body (Neue Haas Display Light)

--rc-text-displayDisplay · 64px

Sell more, everywhere

--rc-text-h1H1 / page title · 48px

Retail, in a circle

--rc-text-h2H2 / section · 36px

One platform

--rc-text-h3H3 · 28px

Built for merchants

--rc-text-h4H4 / card heading · 22px

Section heading

--rc-text-body-lgLead / large control · 18px

Lead paragraph / large button

--rc-text-bodyBody (default) · 16px

Body text — the default paragraph size across the site.

--rc-text-captionCaption / legal · 13px

Caption / helper / legal text.

Spacing — tapered scale

Non-linear 8px-based ramp: tight at the small end (4 / 8 / 12 for icon gaps and dense stacks), wide jumps at the top (48 / 64 for section rhythm).

--rc-space-14px
--rc-space-28px
--rc-space-312px
--rc-space-416px
--rc-space-524px
--rc-space-632px
--rc-space-748px
--rc-space-864px

Radii

--rc-radius-sm8px
--rc-radius-md12px
--rc-radius-lg20px
--rc-radius-fullpill

Breakpoints

The canonical responsive stops. CSS variables can't be used inside@media — treat these as the single reference every component's media queries must match (mobile-first: min-width).

--rc-bp-sm640px · Phone → large phone
--rc-bp-md900px · Tablet
--rc-bp-lg1200px · Laptop / desktop
--rc-bp-xl1440px · Wide desktop

Elevation

On the dark theme, depth comes from lighter surfaces, not drop shadows (dark shadows are invisible on a dark background). Stack surface tiers for cards and panels; reach for a shadow token only for the CTA glow or a truly floating layer.

--rc-bg#1c1c1fPage background (base)
--rc-surface#333336Raised card / panel
--rc-surface-raised#3d3d42Higher card / modal body
--rc-surface-2#484853Highest surface

Shadows

The only two shadows that read on dark: the CTA glow and one overlay for floating layers.

--rc-shadow-purple
--rc-shadow-overlay

Motion

The signature interaction is a subtle press on hover, over one shared duration. Hover the tiles. Every interactive element should reuse these — don't invent new durations or easings.

--rc-pressscale(.97) — buttons, cards, tiles
--rc-press-widescale(.99) — full-width / large blocks
--rc-transition.3s — the one duration for all state changes

Buttons

The one canonical <Button> — the full emphasis ladder (primary › secondary › ghost) × two sizes, live. Styled entirely fromtokens.css. Use one primary CTA per view.

variant="primary"

variant="secondary"

variant="ghost"

full (width-100)

As link (href → renders <a>)

States (hover / focus me · disabled)

Copy

<Button variant="primary" size="md" href="/signup">Get started</Button>

Do

  • Exactly one primary per view — it's the single main action.
  • Use secondary / ghost for everything else.
  • Set href for navigation, omit it for form/JS actions.

Don't

  • Stack two primary buttons side by side.
  • Author raw w-button / <a class="button"> markup.
  • Hard-code padding or colour — the variant already carries it.

Components

The canonical building blocks — each token-driven, so a brand change intokens.css updates them everywhere. Use these instead of authoring bespoke markup.

<Card> — surface container

Solid (default)

The workhorse content card — opaque --rc-surface with a hairline border.

Solid · raised

One step lighter (--rc-surface-raised) for the card that must pop.

Glass

Signature glassmorphism — use over imagery / a glow, not the flat page bg.

Link card →

Pass href — whole card becomes a link with the press + accent edge.

<Card variant="glass" raised>…</Card>

<Input> — text field

We'll never share it.

Enter a valid https:// URL.

<Input id="email" label="Work email" type="email" error="…" />

<Link> & <Badge>

Inline links use the Link component andopen external tabs safely. Buttons are for actions — links are for navigation inside copy.

NeutralNewActivePendingFailed
<Badge tone="success">Active</Badge>   <Link href="/x">read more</Link>