Art Nouveau DLS Download .md

Art Nouveau Design Language System

Tokens, ornament rules and components for building web, editorial and mobile interfaces from flowing lines, warm vellum and gilded detail. Ready for CSS, Tailwind and Figma.

0. System Architecture at a Glance

Ornament density in practice

L0 Functional

Hairline border only.

L1 Refined

Asymmetric corners, gilt inner line.

L2 Ornate

Triple frame and arched head.

L3 Showpiece

Leaded glass and backlight.

The DLS uses three token layers. Components only ever consume the semantic layer, so a brand can re-skin the system (for example, a Mucha-style poster palette versus a Tiffany-style glass palette) by editing primitives alone.

Layer Prefix Example Consumed by
Primitive --an-{hue}-{step} --an-moss-900: #2D3B2D Semantic tokens only
Semantic --an-{role} --an-text, --an-surface, --an-accent Components
Component --an-btn-*, --an-card-* --an-btn-bg Individual components

Ornament density levels (set per page region with data-ornament):

Level Name Use Ornament allowed
L0 Functional Data tables, checkout, dense dashboards Hairline borders only
L1 Refined App UI, forms, settings Corner flourishes, leaf focus rings
L2 Ornate Editorial articles, product pages Cartouches, tendril dividers, drop-caps
L3 Showpiece Landing heroes, campaign pages, 404s Full whiplash frames, stained-glass panels

1. Design Philosophy & Aesthetic Principles

1.1 Emotional Tone

Art Nouveau (c. 1890–1910: Mucha, Gallé, Tiffany, Guimard, Horta) rejected industrial repetition and borrowed its grammar from stems, tendrils, insect wings and water. The digital translation keeps that warmth and rejects kitsch.

Trait What the user feels How it appears in the UI Guardrail
Organic Growth, living material Curved containers, asymmetric balance, no hard 90° boxes at L2/L3 Never at the cost of readable grid alignment for text
Graceful Ease, unhurried calm Slow easing, generous whitespace, long line-height No bounce or elastic overshoot
Ornate Richness, craft Filigree, frames, cartouches Ornament budget (see 1.3)
Sensual Warmth, touch Warm light, soft shadows, rounded press depth Never glossy or plastic
Handcrafted Human maker Slightly irregular line weight, tapered strokes Irregularity is designed once and reused, never random per render
Nature-inspired Botanical, aquatic Ginkgo, iris, water lily, peacock, dragonfly motifs Stylised and flattened, never photographic clip-art

1.2 Core Tenets

  1. The line is alive. Every border, divider and underline is a drawn curve with a pen-pressure feel (taper from 2.5px to 0.75px), not a CSS 1px solid default. Plain CSS borders are used only at L0.
  2. The S-curve rule (whiplash). Decorative paths must contain at least one inflection point, where curvature reverses. A path that only bows one way reads as a generic rounded corner, not Nouveau.
  3. Botanical asymmetry. Balance by weight, not mirror. A flourish on the top-left is answered by a smaller, differently shaped one at the bottom-right. Use roughly a 3:2 visual weight ratio.
  4. Craft integrated with structure. Ornament is the container, not a sticker on it. The frame is the card border, the tendril is the divider, the leaf is the focus ring. If you can delete an ornament and nothing structural changes, move it into the structure or remove it.
  5. Abstract nature. Reduce plants and animals to flowing silhouettes with 3–5 shape primitives. No gradients inside motif icons beyond a single flat tint plus a lead outline.
  6. Material honesty. Surfaces imitate vellum, enamel, stained glass, patinated copper and gilt. Each has a defined token set (Sections 2 and 3), and they are never mixed on a single element.
  7. Modern translation. Responsive, accessible, performant. Ornament is vector (SVG/CSS), lazy-loaded, and removable at L0 without layout shift.

1.3 Ornament Budget (anti-kitsch rules)

  • One hero flourish per viewport (a large whiplash frame, cartouche or illustration).
  • Maximum two accent hues plus gold in any single component.
  • Gold is decoration, never text on light surfaces (see contrast data in Section 2).
  • Ornaments never overlap body text. Reserve a 16px safe zone (--an-safe) between filigree and copy.
  • On screens under 480px, drop the ornament level by one (L3 → L2, L2 → L1).

2. Color Palette & Organic Surface Tokens

Palette

Vellum#F5F0EB--an-vellum
Ivory#EDE4D3--an-ivory
Parchment#E3D6BF--an-parchment
Moss 900#2D3B2D--an-moss-900
Moss 950#1B251B--an-moss-950
Lead#3A2E26--an-lead
Bronze#6B4E2E--an-bronze
Teal 500#2A8A94--an-teal-500
Teal 700#17606A--an-teal-700
Rose 500#C99A98--an-rose-500
Rose 700#8A4B4F--an-rose-700
Ochre 500#B5651D--an-ochre-500
Ochre 700#8F4A0F--an-ochre-700
Sage 500#9CAF88--an-sage-500
Sage 700#5E7352--an-sage-700
Copper 500#B87333--an-copper-500
Copper 700#8A4F1E--an-copper-700
Gold 500#D4AF37--an-gold-500
Gold 700#7A5C0F--an-gold-700

Gradients

paper
pond
peacock
moss
gilt

Contrast on vellum

Moss 900 · 10.5:1

Teal 700 · 6.4:1

Gold 700 · 5.5:1

Gold 500 · 1.9:1 (decoration only)

2.1 Natural Foundation

Token Hex Role
--an-vellum #F5F0EB Primary page background (warm parchment/vellum)
--an-ivory #EDE4D3 Antique ivory: raised surfaces, input fields
--an-parchment #E3D6BF Aged parchment: wells, table stripes, pressed state
--an-moss-900 #2D3B2D Deep moss: primary text, dark surfaces
--an-moss-800 #3B4D3B Dark surface variant
--an-moss-950 #1B251B Footer, deepest background, text on gold
--an-lead #3A2E26 Burnt charcoal: lead lines, stained-glass cames
--an-bronze #6B4E2E Secondary linework, wrought-iron nav

2.2 Art Nouveau Accent Palette

Each hue has a decorative step (fills, borders, glass tints) and a text-safe step (dark enough for AA text on vellum). Always pick the step for the job.

Hue Decorative token Hex Text/UI-safe token Hex Contrast of text-safe step on #F5F0EB
Peacock teal --an-teal-500 #2A8A94 --an-teal-700 #17606A 6.4 : 1
Dusty rose --an-rose-500 #C99A98 --an-rose-700 #8A4B4F 5.8 : 1
Burnt ochre --an-ochre-500 #B5651D --an-ochre-700 #8F4A0F 5.9 : 1
Sage --an-sage-500 #9CAF88 --an-sage-700 #5E7352 4.6 : 1
Warm copper --an-copper-500 #B87333 --an-copper-700 #8A4F1E 5.8 : 1
Gilded gold --an-gold-500 #D4AF37 --an-gold-700 #7A5C0F 5.5 : 1

Extra tints: --an-gold-300 #E8D48A, --an-sage-300 #C5D1B5, --an-rose-300 #E6CFCD, --an-teal-300 #A9CFD3, --an-teal-900 #0F3F46.

Ratios are calculated with the WCAG 2.1 relative-luminance formula and rounded. Re-verify in your tooling (Stark, Figma contrast plugins, axe) after any hex edit.

Key contrast facts

Pair Ratio Verdict
--an-moss-900 on --an-vellum ~10.5 : 1 AAA body text
--an-gold-500 on --an-vellum ~1.9 : 1 Fails. Decoration only
--an-gold-500 on --an-moss-900 ~5.6 : 1 AA text and icons on dark
--an-copper-500 on --an-vellum ~3.4 : 1 Passes 3:1 for borders and icons, not text
--an-teal-500 on --an-vellum ~3.6 : 1 Large text (24px+ or 19px bold) and UI only
--an-vellum on --an-teal-700 ~6.4 : 1 Button label

2.3 Semantic Tokens

:root {
  /* primitives */
  --an-vellum:#F5F0EB; --an-ivory:#EDE4D3; --an-parchment:#E3D6BF;
  --an-moss-950:#1B251B; --an-moss-900:#2D3B2D; --an-moss-800:#3B4D3B;
  --an-lead:#3A2E26; --an-bronze:#6B4E2E;
  --an-teal-300:#A9CFD3; --an-teal-500:#2A8A94; --an-teal-700:#17606A; --an-teal-900:#0F3F46;
  --an-rose-300:#E6CFCD; --an-rose-500:#C99A98; --an-rose-700:#8A4B4F;
  --an-ochre-500:#B5651D; --an-ochre-700:#8F4A0F;
  --an-sage-300:#C5D1B5; --an-sage-500:#9CAF88; --an-sage-700:#5E7352;
  --an-copper-500:#B87333; --an-copper-700:#8A4F1E;
  --an-gold-300:#E8D48A; --an-gold-500:#D4AF37; --an-gold-700:#7A5C0F;

  /* semantic */
  --an-bg: var(--an-vellum);
  --an-surface: var(--an-ivory);
  --an-surface-sunken: var(--an-parchment);
  --an-text: var(--an-moss-900);
  --an-text-muted: #4F5B4A;            /* ~6.6:1 on vellum */
  --an-text-accent: var(--an-teal-700);
  --an-link: var(--an-teal-700);
  --an-link-hover: var(--an-teal-900);
  --an-line: var(--an-lead);
  --an-line-soft: color-mix(in srgb, var(--an-bronze) 35%, transparent);
  --an-gild: var(--an-gold-500);       /* decoration only on light */
  --an-gild-text: var(--an-gold-700);  /* text-safe gold on light */
  --an-focus: var(--an-teal-700);
  --an-danger: #9B2F2F;                /* ~6.6:1 on vellum */
  --an-success: var(--an-sage-700);
  --an-warning: var(--an-ochre-700);
  --an-safe: 16px;
}

[data-theme='night'] {
  --an-bg: var(--an-moss-950);
  --an-surface: var(--an-moss-900);
  --an-surface-sunken: #121A12;
  --an-text: var(--an-vellum);
  --an-text-muted: #CFC8B8;
  --an-text-accent: var(--an-gold-500);
  --an-link: var(--an-gold-300);
  --an-link-hover: #FFF1B8;
  --an-line: var(--an-gold-500);
  --an-gild-text: var(--an-gold-500);
  --an-focus: var(--an-gold-300);
}

2.4 Gradients & Atmospheric Surfaces

Gradients are soft, low-chroma and warm. Maximum two stops of hue plus a neutral, with at most a 12% lightness change. Never use saturated or neon colors, and never cool-white highlights.

Token Definition Use
--an-grad-paper linear-gradient(170deg,#F8F4EE 0%,#F5F0EB 55%,#EFE6D8 100%) Page background
--an-grad-dawn radial-gradient(120% 90% at 20% 0%,#F3E3D2 0%,transparent 60%) Warm atmospheric tint, hero corner
--an-grad-pond linear-gradient(160deg,#A9CFD3 0%,#C5D1B5 100%) Water-lily / pond feature panels
--an-grad-peacock linear-gradient(155deg,#17606A 0%,#0F3F46 100%) Dark feature panels, hero buttons
--an-grad-moss linear-gradient(180deg,#3B4D3B 0%,#1B251B 100%) Footer, night theme
--an-grad-gilt linear-gradient(110deg,#B8932A 0%,#E8D48A 38%,#D4AF37 55%,#9C7A1C 100%) Gilded strokes and borders (never behind text)
--an-glow-gilt 0 0 0 1px rgba(212,175,55,.55), 0 0 18px rgba(212,175,55,.35) Hover and active glow

Surface contrast rules

  1. Text sits on flat or near-flat surfaces. If a gradient lies behind text, the lightest and darkest points must both still meet 4.5:1.
  2. Metallic highlights (gilt, copper) are 1–2px lines, small icons or glows, never full-bleed fills behind copy.
  3. Elevation is expressed by warm shadows (rgba(58,46,38,.18)), never grey or black ones.
  4. A subtle paper grain (SVG noise at 3–4% opacity, mix-blend-mode: multiply) is optional at L2/L3.
body {
  background: var(--an-grad-paper), var(--an-bg);
  color: var(--an-text);
}
.an-grain::after {
  content:''; position:absolute; inset:0; pointer-events:none; opacity:.04; mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}

3. Decorative Linework, Motifs & Border Engine

Tendril divider

Triple-line frame with corner flourish

Ornament is the container. The frame is the card border, so removing it changes the structure.

Stained-glass panes

Teal
Rose, leaded
Ochre
Sage

3.1 Whiplash Vector Mechanics

The coup de fouet (whiplash) is a curve that swells, reverses direction and snaps into a tight terminal curl. Use these rules for every authored SVG path.

Parameter Rule
Inflections At least 1 per path; 2 for dividers longer than 240px
Curve type Cubic Béziers (C / S), with smooth joins (control handles collinear)
Handle ratio Control-point length = 30–45% of segment length (a longer handle gives a lazier, more organic swing)
Terminals End in a spiral curl (r 4–10px) or a leaf-point; never a blunt butt cap on decorative paths
Stroke weight Tapers 2.5px (root) → 0.75px (tip). For true taper, draw as a filled outline path; for simple cases, use stroke-width: 1.5 with stroke-linecap: round
Asymmetry Left/right or top/bottom halves differ in length by about 3:2
Vine branching Side shoots leave the stem at 25–50°, alternate sides, and shrink 15–25% per generation (max 3 generations)
Stroke color currentColor, so ornaments inherit the theme (--an-line, --an-gild, etc.)
Optimisation Max 12 anchor points per path, 2-decimal precision, inline <symbol> sprites

Tendril divider (reusable SVG)

<svg class='an-divider' viewBox='0 0 480 48' fill='none' stroke='currentColor'
     stroke-width='1.5' stroke-linecap='round' aria-hidden='true' focusable='false'>
  <!-- main stem: two inflections -->
  <path d='M4 26 C52 4 88 46 150 26 S214 6 240 26 S306 46 342 26 S424 6 476 24'/>
  <!-- central curl, answered by a smaller counter-curl -->
  <path d='M240 26 c-4-15 10-23 18-13 c6 8-3 15-9 10'/>
  <path d='M150 26 c4 11-5 17-11 12 c-4-4 0-9 4-7'/>
  <!-- leaf -->
  <path d='M342 26 c6-10 17-12 22-10 c-2 9-11 15-22 10 z'/>
</svg>
.an-divider { width:100%; max-width:480px; height:auto; color:var(--an-gild); margin-inline:auto; display:block; }
/* On light surfaces pair gold with a bronze under-stroke to keep the line visible */
.an-divider { filter: drop-shadow(0 1px 0 color-mix(in srgb, var(--an-bronze) 40%, transparent)); }

Decorative dividers are aria-hidden. Semantic separation uses <hr> or heading structure (see Section 6).

3.2 Frame & Border Specifications

Frame Construction Use
Hairline (L0) 1px solid var(--an-line-soft) Functional UI
Triple-line (L1) Outer 2px lead, 1px gilt gap line, 1px bronze inner (CSS below) Cards, modals, inputs
Arched frame (L2) Triple-line + border-radius: 999px 999px 12px 12px top arch Feature cards, portraits, product images
Cartouche (L2) Ellipse/lozenge SVG nine-slice with scroll terminals Pull-quotes, badges, section titles
Whiplash frame (L3) Full SVG border-image with corner flourishes Hero panels, campaign pages

Triple-line frame (pure CSS)

.an-frame {
  position: relative;
  background: var(--an-surface);
  border: 2px solid var(--an-lead);
  border-radius: 14px 28px 14px 28px;           /* asymmetric: 1:2 alternation */
  outline: 1px solid var(--an-gild);
  outline-offset: -7px;                         /* inner gilt hairline */
  box-shadow:
    0 0 0 4px var(--an-bg),                     /* breathing gap */
    0 0 0 5px var(--an-copper-500),             /* outer copper hairline */
    0 10px 28px -12px rgba(58,46,38,.35);       /* warm elevation */
  padding: calc(var(--an-safe) * 1.5);
}

Arched corner flourish (inline SVG, reusable on all four corners via transforms)

.an-flourish::before,
.an-flourish::after {
  content:''; position:absolute; width:56px; height:56px; pointer-events:none;
  background: no-repeat center / contain
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 56 56' fill='none' stroke='%23B8932A' stroke-width='1.5' stroke-linecap='round'><path d='M2 54 C2 24 24 2 54 2'/><path d='M10 54 C10 32 30 10 54 10' stroke-width='1'/><path d='M2 30 c-3-9 6-14 11-8 c3 4-1 8-5 6'/><path d='M30 2 c9-3 14 6 8 11 c-4 3-8-1-6-5'/></svg>");
}
.an-flourish::before { top:-6px; left:-6px; }
.an-flourish::after  { bottom:-6px; right:-6px; transform: rotate(180deg) scale(.8); } /* smaller answer = asymmetry */

Filigree header (section header lockup)

<header class='an-filigree'>
  <svg class='an-filigree__wing' aria-hidden='true'><use href='#an-wing'/></svg>
  <h2 class='an-h2'>The Iris Collection</h2>
  <svg class='an-filigree__wing an-filigree__wing--r' aria-hidden='true'><use href='#an-wing'/></svg>
</header>
.an-filigree { display:grid; grid-template-columns: 1fr auto 1fr; align-items:center; gap:var(--an-safe); color:var(--an-gild); }
.an-filigree__wing { width:100%; height:24px; }
.an-filigree__wing--r { transform: scaleX(-1) scaleY(.85); } /* mirrored but not identical */

3.3 Stained Glass & Enamel Surface Math

Glass anatomy: a tinted translucent pane, a lead came (dark outline), and light that bleeds from behind.

Layer Spec
Pane tint Hue at 22–35% alpha over --an-vellum (light) or 30–45% over moss (night)
Lead came 1.5px solid var(--an-lead) for panes, 2px for the outer frame, 1px for fine divisions
Backlight Radial gradient of warm gold at 25–40% alpha from the pane centre or the top
Edge luminance Inset glow inset 0 0 24px rgba(232,212,138,.28)
Blur backdrop-filter: blur(6px) saturate(1.1) (optional; fall back to a solid tint)
Text on glass Always use --an-moss-900 (light) or --an-vellum (night). Verify 4.5:1 against the worst-case pane color (lightest tint over lightest background)

Pane tint tokens

Token RGBA Looks like
--an-glass-teal rgba(42,138,148,.28) Peacock-feather pane
--an-glass-rose rgba(201,154,152,.34) Dusty-rose pane
--an-glass-ochre rgba(181,101,29,.26) Amber pane
--an-glass-sage rgba(156,175,136,.34) Leaf pane
--an-glass-gold rgba(212,175,55,.22) Lamplit pane
.an-glass {
  --pane: var(--an-glass-teal);
  position: relative;
  isolation: isolate;
  background:
    radial-gradient(70% 60% at 50% 0%, rgba(232,212,138,.40), transparent 70%),  /* backlight */
    var(--pane);
  border: 1.5px solid var(--an-lead);                    /* lead came */
  border-radius: 999px 999px 10px 10px;                  /* arched window */
  box-shadow:
    inset 0 0 24px rgba(232,212,138,.28),                /* luminous edge */
    inset 0 0 0 4px color-mix(in srgb, var(--an-bg) 60%, transparent), /* matte mat */
    0 14px 30px -14px rgba(58,46,38,.45);
  backdrop-filter: blur(6px) saturate(1.1);
}
/* Lead divisions: a grid of thin lines drawn with gradients */
.an-glass--leaded {
  background-image:
    linear-gradient(var(--an-lead), var(--an-lead)),
    linear-gradient(90deg, var(--an-lead), var(--an-lead)),
    radial-gradient(70% 60% at 50% 0%, rgba(232,212,138,.40), transparent 70%);
  background-size: 100% 1.5px, 1.5px 100%, 100% 100%;
  background-position: 0 38%, 50% 0, 0 0;
  background-repeat: no-repeat;
  background-color: var(--pane);
}
@supports not (backdrop-filter: blur(1px)) { .an-glass { background-color: var(--an-ivory); } }

Enamel (cloisonné) variant: opaque pane (--an-teal-700, --an-rose-700 etc.), a 1px gilt cell wall (outline: 1px solid var(--an-gild)), and a top-left specular highlight linear-gradient(135deg, rgba(255,255,255,.18), transparent 40%). It works well for badges and tags, with --an-vellum text.

4. Typography & Floral Ornamentation

Specimen

Sinuous lines, living type

Cormorant Garamond for subheads, set at 22px and up

Every stem curves twice before it reaches the flower. The drop-cap borrows that gesture: a live letter held inside a gilt tendril, readable by screen readers and sized down on small screens.

  • Ginkgo leaf is the default bullet
  • Water lily marks feature lists
  • Iris bud marks nested items

4.1 Type Families

Role Premium (licensed) Open-source production stack Notes
Display / H1–H2 Eckmann, Willow, Parisish, Mulberry Sans, Royal Acid Fraunces (variable; SOFT 100, WONK 1, opsz 144) Fraunces gives high contrast with soft, inky terminals that read as organic. Use the premium faces for logos and posters only, since their irregular letterforms lose legibility below 32px
Subhead / H3–H4 Cormorant Garamond SemiBold Cormorant Garamond 600 Elegant high-contrast serif. Use at 22px and up
Body (long-form) EB Garamond, Lora Lora 400/500 (or EB Garamond at 20px+) Lora holds up better at 17–19px on screens than thin Garamonds
UI / labels / captions Alegreya Sans Alegreya Sans 500/700 A humanistic sans with calligraphic rhythm, good for buttons and inputs
Numerals / data Lora lining figures font-variant-numeric: lining-nums tabular-nums Keep old-style figures for editorial prose only

Keep to a maximum of three families per page (display, body, UI). Self-host WOFF2 with font-display: swap, subset to Latin plus the ornament glyphs you use, and preload the display and body files only.

4.2 Type Scale (fluid, 1.25 major-third with an editorial bump at display sizes)

Token Font Size (clamp) Line-height Tracking Weight
--an-fs-display Display clamp(3rem, 2rem + 5vw, 6rem) 1.02 -0.01em 600
--an-fs-h1 Display clamp(2.25rem, 1.6rem + 3vw, 3.75rem) 1.08 -0.005em 600
--an-fs-h2 Display clamp(1.75rem, 1.4rem + 1.6vw, 2.5rem) 1.15 0 600
--an-fs-h3 Cormorant clamp(1.375rem, 1.2rem + .8vw, 1.75rem) 1.25 0.005em 600
--an-fs-body Lora clamp(1.0625rem, 1rem + .3vw, 1.1875rem) 1.7 0 400
--an-fs-ui Alegreya Sans 1rem 1.4 0.02em 500
--an-fs-caption Alegreya Sans .875rem 1.45 0.03em 500
--an-fs-overline Alegreya Sans .8125rem 1.3 0.16em, uppercase 700
:root {
  --an-font-display: 'Fraunces', 'Cormorant Garamond', Georgia, serif;
  --an-font-serif:   'Cormorant Garamond', 'EB Garamond', Georgia, serif;
  --an-font-body:    'Lora', 'EB Garamond', Georgia, serif;
  --an-font-ui:      'Alegreya Sans', 'Source Sans 3', system-ui, sans-serif;
  --an-measure: 66ch;                       /* optimal line length: 60-72 characters */
}
body { font-family: var(--an-font-body); font-size: var(--an-fs-body); line-height: 1.7; }
h1, h2, .an-display {
  font-family: var(--an-font-display);
  font-variation-settings: 'SOFT' 100, 'WONK' 1, 'opsz' 144;
  font-weight: 600; text-wrap: balance; color: var(--an-text);
}
p, li { max-width: var(--an-measure); text-wrap: pretty; hanging-punctuation: first; }
.an-overline { font: 700 .8125rem/1.3 var(--an-font-ui); letter-spacing: .16em; text-transform: uppercase; color: var(--an-gild-text); }

If you use a licensed face such as Eckmann for display, apply it only to .an-display--lettering (logo, hero word, poster headline) at 40px or larger, keep the semantic heading in the DOM, and give it a Fraunces fallback so the page never depends on one font file.

4.3 Floral Drop-Caps

The drop-cap occupies 3 lines and sits inside a tendril-wrapped medallion. The letter itself stays live text (screen readers read it normally); the tendril is a background SVG.

.an-dropcap::first-letter {
  font-family: var(--an-font-display);
  font-weight: 700;
  font-size: 4.6em;
  line-height: .82;
  float: left;
  padding: .08em .14em .02em .06em;
  margin: .04em .12em 0 0;
  color: var(--an-teal-700);
  background:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' fill='none' stroke='%23B8932A' stroke-width='1.6' stroke-linecap='round'><path d='M6 70 C2 36 30 6 64 8 C86 10 96 28 92 44'/><path d='M12 94 C34 84 48 90 62 78'/><path d='M92 44 c8-6 4-18-6-16'/><path d='M6 70 c-6 6-2 16 6 14'/></svg>") no-repeat center / 118% 118%;
}
@media (max-width: 480px) { .an-dropcap::first-letter { font-size: 3.4em; } }

4.4 Ornamental Bullets & Section Marks

Bullets are SVG masks, 1em square, colored with background-color through the mask so they inherit the theme.

Ornament Token Use
Ginkgo leaf --an-bullet-ginkgo Default list bullet (editorial)
Water lily --an-bullet-lily Feature lists, pricing benefits
Peacock feather --an-bullet-peacock Highlights and "new" markers
Iris bud --an-bullet-iris Nested (level 2) lists
Dragonfly --an-mark-dragonfly Section end-mark (replaces the fleuron)
.an-list { list-style: none; padding-inline-start: 0; }
.an-list > li { position: relative; padding-inline-start: 1.75em; margin-block: .55em; }
.an-list > li::before {
  content: ''; position: absolute; inset-inline-start: 0; top: .38em; width: 1.05em; height: 1.05em;
  background-color: var(--an-teal-700);
  -webkit-mask: var(--an-bullet-ginkgo) no-repeat center / contain;
          mask: var(--an-bullet-ginkgo) no-repeat center / contain;
}
/* ginkgo leaf: fan-shaped with a central notch */
:root {
  --an-bullet-ginkgo: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 22 V13 M12 13 C6 13 2 8 3 3 C6 5 9 5 12 8 C15 5 18 5 21 3 C22 8 18 13 12 13 Z' fill='black'/></svg>");
}
.an-list--lily > li::before { -webkit-mask-image: var(--an-bullet-lily); mask-image: var(--an-bullet-lily); background-color: var(--an-rose-700); }

Section ornaments: use a centered tendril divider (3.1) for chapter breaks, a single dragonfly mark for end-of-article, and a small three-leaf cluster as the <hr> replacement inside long prose.

5. Component Specifications & Mechanics

Buttons

Ghost link

Form field (focus it)

We write twice a season.

Arch card

Collection No. 7
The Iris Folio

Twelve plates of swaying stems, printed on cotton rag.

View the folio

Navigation with arched dropdown

All components inherit: warm shadows, asymmetric radii, lead-line borders, --an-focus focus ring, and the motion tokens from Section 6. Minimum touch target is 44×44px.

5.1 Buttons & Interactive Controls

Variant Surface Border Label Hover Active (pressed)
Primary --an-grad-peacock 1.5px --an-lead + 1px inner gilt --an-vellum, Alegreya Sans 700 Gilt glow --an-glow-gilt, lift 1px Inset shadow, translateY(1px), glow fades
Secondary Transparent over --an-surface 1.5px --an-teal-700 --an-teal-700 Fills with --an-teal-300 at 35% Fills with --an-teal-300 at 55%
Gilded (hero only) --an-moss-950 1.5px --an-gold-500 --an-gold-300 (9:1 on moss) Gilt glow + shimmering border sweep Inset glow
Ghost / text None Underline as drawn tendril --an-link Tendril lengthens (background-size) Color --an-link-hover
Icon button --an-ivory Arched (999px 999px 10px 10px) Icon --an-moss-900 Gilt glow Inset

Silhouette: the base shape is a "pointed arch pill": border-radius: 28px 28px 28px 10px, a slightly different corner from the others, which lends hand-cut character without compromising the hit area.

.an-btn {
  --btn-bg: var(--an-grad-peacock);
  --btn-fg: var(--an-vellum);
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: .6em;
  min-height: 44px; padding: .75em 1.6em;
  font: 700 1rem/1.2 var(--an-font-ui); letter-spacing: .04em;
  color: var(--btn-fg); background: var(--btn-bg);
  border: 1.5px solid var(--an-lead);
  border-radius: 28px 28px 28px 10px;
  box-shadow: inset 0 0 0 3px rgba(232,212,138,.55), 0 6px 14px -8px rgba(58,46,38,.55);
  cursor: pointer;
  transition: box-shadow var(--an-dur-md) var(--an-ease-vine),
              transform var(--an-dur-sm) var(--an-ease-water),
              filter var(--an-dur-md) var(--an-ease-vine);
}
.an-btn:hover  { box-shadow: inset 0 0 0 3px rgba(232,212,138,.9), var(--an-glow-gilt); transform: translateY(-1px); }
.an-btn:active { transform: translateY(1px); box-shadow: inset 0 3px 8px rgba(0,0,0,.35); filter: brightness(.96); }
.an-btn:focus-visible { outline: 3px solid var(--an-focus); outline-offset: 3px; }
.an-btn[aria-disabled='true'] { opacity: .55; cursor: not-allowed; box-shadow: none; }
.an-btn--secondary { --btn-bg: transparent; --btn-fg: var(--an-teal-700); border-color: var(--an-teal-700); box-shadow: none; }
.an-btn--secondary:hover { background: color-mix(in srgb, var(--an-teal-300) 35%, transparent); }

Ghost-link tendril underline

.an-link {
  color: var(--an-link);
  text-decoration: underline 1px;              /* static underline stays as the baseline */
  text-underline-offset: .22em;
  background: no-repeat left bottom / 0% 6px
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 6' preserveAspectRatio='none' fill='none' stroke='%2317606A' stroke-width='1.4'><path d='M0 4 C20 0 30 6 50 3 S80 0 100 3'/></svg>");
  transition: background-size var(--an-dur-md) var(--an-ease-vine);
}
.an-link:hover, .an-link:focus-visible { background-size: 100% 6px; }

5.2 Cards & Content Containers

Card type Shape Header Surface Shadow / depth
Arch card (default L2) Top arch 999px 999px 14px 14px image window, body below Cartouche banner overlapping the arch base --an-surface Triple-line frame + warm lift
Asymmetric card (L1) 14px 28px 14px 28px Overline + H3, with a short tendril under it --an-surface Hairline + soft shadow
Glass card (L3) Arched window (3.3) Gilt overline Pane tint + backlight Luminous inset
Data card (L0) 6px radius Plain --an-bg 1px --an-line-soft

Inner vignette: to give the vellum a lived-in feel, add box-shadow: inset 0 0 60px rgba(139,105,60,.14), a warm sepia shading at the edges only (never greater than 18% alpha).

<article class='an-card an-card--arch an-flourish'>
  <figure class='an-card__arch'><img src='iris.jpg' alt='Hand-colored iris lithograph' loading='lazy'></figure>
  <div class='an-card__banner'><span class='an-overline'>Collection No. 7</span></div>
  <div class='an-card__body'>
    <h3 class='an-h3'>The Iris Folio</h3>
    <p>Twelve plates of swaying stems, printed on cotton rag.</p>
    <a class='an-btn an-btn--secondary' href='#'>View the folio</a>
  </div>
</article>
.an-card { position: relative; background: var(--an-surface); border: 2px solid var(--an-lead);
  border-radius: 14px 28px 14px 28px; box-shadow: inset 0 0 60px rgba(139,105,60,.14), 0 10px 28px -14px rgba(58,46,38,.4); }
.an-card--arch { border-radius: 999px 999px 14px 14px / 40% 40% 14px 14px; }
.an-card__arch { margin: 10px; aspect-ratio: 4/5; overflow: hidden; border-radius: 999px 999px 8px 8px; border: 1.5px solid var(--an-gild); }
.an-card__arch img { width: 100%; height: 100%; object-fit: cover; }
.an-card__banner { display:grid; place-items:center; margin: -22px 24px 0; position:relative; padding:.5em 1.2em;
  background: var(--an-vellum); border: 1.5px solid var(--an-lead); border-radius: 999px 999px 999px 8px; }
.an-card__body { padding: calc(var(--an-safe) * 1.5); display: grid; gap: .75rem; }

5.3 Form Fields & Inputs

Anatomy: a parchment-tinted field framed by a delicate double stroke, with the label above in Alegreya Sans, helper text below, and a leaf or tendril motif that grows on focus. The leaf is additional to a standard high-contrast focus outline, never a replacement for it.

State Field background Border Extra
Default --an-ivory 1.5px --an-bronze (comfortably above 3:1 on vellum) none
Hover --an-ivory --an-copper-700 none
Focus --an-vellum 2px --an-teal-700 3px outer --an-gold-300 ring; leaf tendril unfurls at the right edge
Filled --an-ivory --an-bronze none
Error #F6E3E1 2px --an-danger Thorn icon and text message (not color alone)
Success #E8EFE0 2px --an-sage-700 Leaf-check icon and text message
Disabled --an-parchment 1px dashed --an-line-soft aria-disabled and reduced opacity
.an-field { display: grid; gap: .4rem; position: relative; }
.an-field label { font: 700 .9375rem/1.3 var(--an-font-ui); letter-spacing: .03em; color: var(--an-text); }
.an-input {
  min-height: 48px; padding: .7em 3em .7em 1em;
  font: 400 1rem/1.4 var(--an-font-body); color: var(--an-text);
  background: var(--an-ivory);
  border: 1.5px solid var(--an-bronze);
  border-radius: 10px 20px 10px 20px;
  box-shadow: inset 0 2px 5px rgba(58,46,38,.12), 0 0 0 3px transparent;
  transition: border-color var(--an-dur-md) var(--an-ease-vine), box-shadow var(--an-dur-md) var(--an-ease-vine), background var(--an-dur-md) var(--an-ease-vine);
}
.an-input::placeholder { color: #6A6455; }                 /* verify >= 4.5:1 on ivory in your tooling */
.an-input:hover  { border-color: var(--an-copper-700); }
.an-input:focus-visible {
  outline: 2px solid var(--an-focus); outline-offset: 2px;  /* high-contrast ring, required */
  background: var(--an-vellum);
  box-shadow: inset 0 2px 5px rgba(58,46,38,.08), 0 0 0 5px color-mix(in srgb, var(--an-gold-300) 70%, transparent);
}
/* leaf-tendril unfurl: decorative, sits in the reserved right padding */
.an-field::after {
  content:''; position:absolute; right: 12px; bottom: 12px; width: 26px; height: 26px; opacity: 0; transform: scale(.6) rotate(-25deg); transform-origin: bottom left;
  background: no-repeat center / contain url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 26' fill='none' stroke='%2317606A' stroke-width='1.5' stroke-linecap='round'><path d='M3 23 C4 12 12 5 23 3 C23 14 15 22 3 23 Z'/><path d='M3 23 C9 17 14 12 20 6'/></svg>");
  transition: opacity var(--an-dur-md) var(--an-ease-vine), transform var(--an-dur-lg) var(--an-ease-vine);
  pointer-events: none;
}
.an-field:focus-within::after { opacity: 1; transform: scale(1) rotate(0); }
.an-input[aria-invalid='true'] { border-color: var(--an-danger); border-width: 2px; background: #F6E3E1; }
.an-help, .an-error { font: 500 .875rem/1.45 var(--an-font-ui); }
.an-error { color: var(--an-danger); display: flex; gap: .4em; }  /* prefix with an icon and text */

5.4 Navigation & Header Bars

Desktop: a wrought-iron or stained-glass bar with the logo set in a central cartouche, nav items split asymmetrically (3 left, 2 right), and flowing arched dropdowns.

Part Spec
Bar 72px high, --an-moss-950 (wrought-iron variant) or --an-glass-teal over a deep backdrop (glass variant), a 2px gilt bottom stroke that dips into a shallow S-curve around the logo
Items Alegreya Sans 700, 1rem, tracking .06em, --an-vellum on moss (very high contrast)
Active item Gilt underline plus aria-current='page'
Dropdown Arched panel, border-radius: 0 0 40% 40% / 0 0 14px 14px, --an-surface, triple-line frame, items stagger in at 60ms
Mobile 56px bar, full-screen stained-glass sheet, arched menu items 56px high, close control top-right
.an-nav { position: sticky; top: 0; z-index: 50; min-height: 72px; display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  padding-inline: clamp(1rem, 4vw, 3rem); color: var(--an-vellum); background: var(--an-moss-950);
  border-bottom: 2px solid var(--an-gold-500); }
.an-nav::after { content:''; position:absolute; left:50%; bottom:-14px; width:140px; height:14px; transform:translateX(-50%);
  background: var(--an-moss-950); border: 2px solid var(--an-gold-500); border-top: 0; border-radius: 0 0 70px 70px / 0 0 14px 14px; }
.an-nav a { color: inherit; font: 700 1rem/1 var(--an-font-ui); letter-spacing: .06em; padding: .9em .6em; }
.an-nav a[aria-current='page'] { box-shadow: inset 0 -2px 0 var(--an-gold-500); }
.an-nav a:focus-visible { outline: 3px solid var(--an-gold-300); outline-offset: 2px; }
.an-menu { position: absolute; min-width: 260px; margin-top: 10px; padding: 1rem 1.25rem 1.5rem;
  background: var(--an-surface); color: var(--an-text); border: 2px solid var(--an-lead);
  border-radius: 0 0 40% 40% / 0 0 14px 14px; transform-origin: top center;
  opacity: 0; transform: translateY(-8px) scaleY(.96); visibility: hidden;
  transition: opacity var(--an-dur-md) var(--an-ease-vine), transform var(--an-dur-md) var(--an-ease-vine), visibility 0s linear var(--an-dur-md); }
.an-menu[data-open='true'] { opacity: 1; transform: none; visibility: visible; transition-delay: 0s; }

Dropdowns open on click or Enter/Space (not hover only), close on Esc, and return focus to the trigger. Use aria-expanded and aria-controls.

6. Motion, Micro-Interactions & Accessibility

Vine draw-in, 600ms

Easing curves

vine .45,.05,.25,1
water .37,0,.18,1
sway .4,0,.6,1

6.1 Kinetic Rules

Motion should feel like a vine swaying in a breeze or water finding its level: long ease-in-out curves, soft starts and soft stops, no linear, no spring overshoot.

Token Value Use
--an-ease-vine cubic-bezier(.45, .05, .25, 1) Default: reveals, hovers, color and shadow changes
--an-ease-water cubic-bezier(.37, 0, .18, 1) Press, slide, move across the layout
--an-ease-sway cubic-bezier(.4, 0, .6, 1) Looping idle sway (symmetric)
--an-dur-sm 300ms Hover, press, focus
--an-dur-md 450ms Dropdowns, tooltips, tendril draw
--an-dur-lg 600ms Page-section reveals, modals, ornament unfurl
--an-stagger 60ms (max 6 items) Lists, menu items, card grids
Interaction Choreography
Tendril draw-in SVG path stroke-dasharray equals path length, stroke-dashoffset animates to 0 over 600ms using --an-ease-vine
Leaf unfurl scale(.6) rotate(-25deg) → identity, transform-origin at the stem base, 600ms
Gilt shimmer (hover) A 110° highlight sweeps across the border once, 600ms, no loop
Page / section reveal Fade plus 12px rise, staggered by 60ms
Idle sway (L3 only) ±1.5° rotation, 6–8s loop on hero flourishes, paused when off-screen
Modal Arch opens upward from its base: clip-path: inset(100% 0 0 0 round 999px 999px 0 0) → inset(0) over 600ms
:root {
  --an-ease-vine: cubic-bezier(.45,.05,.25,1);
  --an-ease-water: cubic-bezier(.37,0,.18,1);
  --an-ease-sway: cubic-bezier(.4,0,.6,1);
  --an-dur-sm: 300ms; --an-dur-md: 450ms; --an-dur-lg: 600ms;
}
.an-draw path { stroke-dasharray: var(--len, 600); stroke-dashoffset: var(--len, 600);
  animation: an-draw var(--an-dur-lg) var(--an-ease-vine) forwards; }
@keyframes an-draw { to { stroke-dashoffset: 0; } }
.an-sway { animation: an-sway 7s var(--an-ease-sway) infinite alternate; transform-origin: 50% 100%; }
@keyframes an-sway { from { transform: rotate(-1.5deg); } to { transform: rotate(1.5deg); } }
.an-shimmer:hover::before { animation: an-shimmer var(--an-dur-lg) var(--an-ease-vine) 1; }
@keyframes an-shimmer { from { background-position: -150% 0; } to { background-position: 250% 0; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important; }
  .an-sway { animation: none; }
  .an-draw path { stroke-dashoffset: 0; }          /* draw the finished state immediately */
}

6.2 Accessibility (WCAG 2.1 AA)

Contrast rules for thin and metallic ornament

Element Requirement Implementation
Body and UI text 4.5 : 1 (1.4.3) --an-text and --an-text-muted on --an-bg / --an-surface; --an-moss-900 on vellum is ~10.5:1
Large text (24px+, or 18.66px bold) 3 : 1 Teal-500 allowed here, never for body
Meaningful icons, input borders, focus rings 3 : 1 against adjacent colors (1.4.11) --an-bronze, --an-copper-500 (~3.4:1), --an-teal-700
Antique gold Decorative only on light surfaces (~1.9:1). As text or a meaningful icon use --an-gild-text #7A5C0F (~5.5:1) on light, or --an-gold-500 on moss (~5.6:1) Pair gold hairlines with a bronze or lead under-stroke so the shape remains perceivable
Thin filigree (<2px) Never carries meaning on its own Treated as decoration: aria-hidden='true'; any meaning is duplicated in text or a heavier-weight icon
Text over ornament or glass 4.5 : 1 at the worst-case pixel Keep a 16px --an-safe zone, or put a --an-surface plate behind the copy
Focus indicator (2.4.7) Visible, 3:1, not clipped 2–3px solid --an-focus with 2–3px offset; leaf and glow effects are additional
Target size 44×44px minimum Ornamental corners must never extend or shrink hit areas
Color independence (1.4.1) State is never color-only Error = thorn icon plus message; success = leaf-check plus message; links underlined in prose
Reflow and zoom (1.4.10, 1.4.4) Works at 320px and 200% zoom Ornaments scale with em/%, and the ornament level drops on small screens
Motion (2.3.3, 2.2.2) No flashing; idle motion pausable; prefers-reduced-motion respected See 6.1; sway is L3-only and pauses when out of view
Forced colors (Windows High Contrast) Borders survive See the snippet below
@media (forced-colors: active) {
  .an-frame, .an-card, .an-input, .an-btn { border: 2px solid CanvasText; outline-color: Highlight; box-shadow: none; }
  .an-glass { background: Canvas; backdrop-filter: none; }
  .an-flourish::before, .an-flourish::after { display: none; }
}
@media (prefers-contrast: more) {
  :root { --an-line-soft: var(--an-lead); --an-text-muted: var(--an-moss-900); --an-gild: var(--an-gold-700); }
}

Semantic and screen-reader guidance: decorative SVGs are aria-hidden='true' focusable='false'; drop-caps remain real text in the DOM; section ornaments never replace <h2> or <hr>; dropdown menus use the disclosure pattern with aria-expanded; stained-glass imagery has no text baked into raster images.

7. Implementation Exports

7.1 Tailwind CSS Configuration (v3 tailwind.config.js)

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./src/**/*.{html,js,jsx,ts,tsx,mdx}'],
  theme: {
    extend: {
      colors: {
        vellum: '#F5F0EB', ivory: '#EDE4D3', parchment: '#E3D6BF',
        moss: { 800: '#3B4D3B', 900: '#2D3B2D', 950: '#1B251B' },
        lead: '#3A2E26', bronze: '#6B4E2E',
        teal:   { 300: '#A9CFD3', 500: '#2A8A94', 700: '#17606A', 900: '#0F3F46' },
        rose:   { 300: '#E6CFCD', 500: '#C99A98', 700: '#8A4B4F' },
        ochre:  { 500: '#B5651D', 700: '#8F4A0F' },
        sage:   { 300: '#C5D1B5', 500: '#9CAF88', 700: '#5E7352' },
        copper: { 500: '#B87333', 700: '#8A4F1E' },
        gold:   { 300: '#E8D48A', 500: '#D4AF37', 700: '#7A5C0F' },
      },
      fontFamily: {
        display: ['Fraunces', 'Cormorant Garamond', 'Georgia', 'serif'],
        serif:   ['Cormorant Garamond', 'EB Garamond', 'Georgia', 'serif'],
        body:    ['Lora', 'EB Garamond', 'Georgia', 'serif'],
        ui:      ['Alegreya Sans', 'Source Sans 3', 'system-ui', 'sans-serif'],
      },
      fontSize: {
        display: ['clamp(3rem,2rem+5vw,6rem)', { lineHeight: '1.02', letterSpacing: '-0.01em' }],
        h1: ['clamp(2.25rem,1.6rem+3vw,3.75rem)', { lineHeight: '1.08' }],
        h2: ['clamp(1.75rem,1.4rem+1.6vw,2.5rem)', { lineHeight: '1.15' }],
        h3: ['clamp(1.375rem,1.2rem+.8vw,1.75rem)', { lineHeight: '1.25' }],
        body: ['clamp(1.0625rem,1rem+.3vw,1.1875rem)', { lineHeight: '1.7' }],
      },
      borderRadius: {
        arch: '999px 999px 14px 14px',
        leaf: '14px 28px 14px 28px',
        petal: '28px 28px 28px 10px',
        field: '10px 20px 10px 20px',
      },
      boxShadow: {
        warm: '0 10px 28px -14px rgba(58,46,38,.4)',
        gilt: '0 0 0 1px rgba(212,175,55,.55), 0 0 18px rgba(212,175,55,.35)',
        vignette: 'inset 0 0 60px rgba(139,105,60,.14)',
        glass: 'inset 0 0 24px rgba(232,212,138,.28), 0 14px 30px -14px rgba(58,46,38,.45)',
      },
      backgroundImage: {
        paper: 'linear-gradient(170deg,#F8F4EE 0%,#F5F0EB 55%,#EFE6D8 100%)',
        peacock: 'linear-gradient(155deg,#17606A 0%,#0F3F46 100%)',
        pond: 'linear-gradient(160deg,#A9CFD3 0%,#C5D1B5 100%)',
        gilt: 'linear-gradient(110deg,#B8932A 0%,#E8D48A 38%,#D4AF37 55%,#9C7A1C 100%)',
      },
      transitionTimingFunction: {
        vine: 'cubic-bezier(.45,.05,.25,1)',
        water: 'cubic-bezier(.37,0,.18,1)',
        sway: 'cubic-bezier(.4,0,.6,1)',
      },
      transitionDuration: { sm: '300ms', md: '450ms', lg: '600ms' },
      keyframes: {
        draw: { to: { strokeDashoffset: '0' } },
        sway: { from: { transform: 'rotate(-1.5deg)' }, to: { transform: 'rotate(1.5deg)' } },
      },
      animation: {
        draw: 'draw 600ms cubic-bezier(.45,.05,.25,1) forwards',
        sway: 'sway 7s cubic-bezier(.4,0,.6,1) infinite alternate',
      },
    },
  },
  plugins: [],
};

Example utility composition

<button class='min-h-[44px] rounded-petal border-[1.5px] border-lead bg-peacock px-6 py-3 font-ui font-bold tracking-wide text-vellum
               shadow-warm transition duration-md ease-vine hover:-translate-y-px hover:shadow-gilt active:translate-y-px
               focus-visible:outline focus-visible:outline-[3px] focus-visible:outline-offset-[3px] focus-visible:outline-teal-700
               motion-reduce:transition-none'>
  Begin the journey
</button>

7.2 Figma Variables & Tokens Studio JSON

Figma variable collections

Collection Modes Contents
Primitives none All --an-* hex values, grouped color/moss/900, color/gold/500, etc.
Semantic Day, Night bg, surface, text, text-muted, link, line, gild, gild-text, focus, danger, success (alias to Primitives)
Shape none radius/arch, radius/leaf, radius/petal, radius/field, stroke/lead 1.5, stroke/frame 2, stroke/hair 1
Motion none dur/sm 300, dur/md 450, dur/lg 600; easing as text styles for handoff
Density L0, L1, L2, L3 ornament/visible (boolean), ornament/scale, safe-zone

Tokens Studio (JSON, partial)

{
  "primitives": {
    "color": {
      "vellum":  { "value": "#F5F0EB", "type": "color" },
      "ivory":   { "value": "#EDE4D3", "type": "color" },
      "moss":    { "900": { "value": "#2D3B2D", "type": "color" }, "950": { "value": "#1B251B", "type": "color" } },
      "teal":    { "500": { "value": "#2A8A94", "type": "color" }, "700": { "value": "#17606A", "type": "color" } },
      "rose":    { "700": { "value": "#8A4B4F", "type": "color" } },
      "ochre":   { "700": { "value": "#8F4A0F", "type": "color" } },
      "sage":    { "700": { "value": "#5E7352", "type": "color" } },
      "copper":  { "500": { "value": "#B87333", "type": "color" } },
      "gold":    { "500": { "value": "#D4AF37", "type": "color" }, "700": { "value": "#7A5C0F", "type": "color" } },
      "lead":    { "value": "#3A2E26", "type": "color" }
    }
  },
  "semantic-day": {
    "bg":        { "value": "{primitives.color.vellum}", "type": "color" },
    "surface":   { "value": "{primitives.color.ivory}", "type": "color" },
    "text":      { "value": "{primitives.color.moss.900}", "type": "color" },
    "link":      { "value": "{primitives.color.teal.700}", "type": "color" },
    "gild":      { "value": "{primitives.color.gold.500}", "type": "color" },
    "gild-text": { "value": "{primitives.color.gold.700}", "type": "color" },
    "line":      { "value": "{primitives.color.lead}", "type": "color" }
  },
  "semantic-night": {
    "bg":        { "value": "{primitives.color.moss.950}", "type": "color" },
    "surface":   { "value": "{primitives.color.moss.900}", "type": "color" },
    "text":      { "value": "{primitives.color.vellum}", "type": "color" },
    "link":      { "value": "#E8D48A", "type": "color" },
    "gild-text": { "value": "{primitives.color.gold.500}", "type": "color" },
    "line":      { "value": "{primitives.color.gold.500}", "type": "color" }
  },
  "shape": {
    "radius-arch":  { "value": "999 999 14 14", "type": "borderRadius" },
    "radius-leaf":  { "value": "14 28 14 28", "type": "borderRadius" },
    "radius-petal": { "value": "28 28 28 10", "type": "borderRadius" },
    "stroke-lead":  { "value": "1.5", "type": "borderWidth" }
  },
  "shadow": {
    "warm": { "value": { "x": "0", "y": "10", "blur": "28", "spread": "-14", "color": "#3A2E2666", "type": "dropShadow" }, "type": "boxShadow" },
    "gilt": { "value": { "x": "0", "y": "0", "blur": "18", "spread": "0", "color": "#D4AF3759", "type": "dropShadow" }, "type": "boxShadow" }
  },
  "motion": {
    "dur-sm": { "value": "300", "type": "duration" },
    "dur-md": { "value": "450", "type": "duration" },
    "dur-lg": { "value": "600", "type": "duration" }
  }
}

Figma component construction notes

  • Build ornaments as vector components with stroke bound to variables (Semantic/gild or line), so they re-theme in Night mode.
  • Use Component Properties: Ornament level (L0–L3), Corner flourish (on/off), State (default, hover, focus, pressed, disabled, error).
  • Use Boolean variants for Show filigree, wired to the Density mode so a frame switches L3 → L1 without rebuilding.
  • Use Auto layout with an explicit safe-zone padding variable so ornament never collides with content.
  • Record the prototype easing as custom Bézier (.45, .05, .25, 1) with durations of 300/450/600ms.

8. Quality Checklist (Definition of Done)

Check Pass condition
Whiplash test Every decorative path has at least one inflection and a curled or leaf terminal
Asymmetry test Opposite corners or sides differ in size or shape (about 3:2)
Ornament budget One hero flourish per viewport; no ornament overlaps text
Gold audit No gold-500 text on light surfaces; gild-text used instead
Contrast audit All text 4.5:1 (3:1 for large text), all UI boundaries and focus rings 3:1
Focus audit Every interactive element has a visible :focus-visible ring that is not clipped by ornament
Motion audit Durations 300–600ms, eased with vine or water curves, no linear, no flashing; reduced-motion verified
Performance Ornament SVG sprite < 30KB gzipped; fonts subset; glass backdrop-filter limited to 3 per viewport
Density behavior L3 → L2 → L1 degradation verified at 480px and 320px; zero layout shift when ornament is hidden
Forced-colors and print Borders remain visible in forced-colors; print stylesheet removes glass and gradients, keeps lead lines