# J4M5 Design System — LLM Guide
> Version 1.0 · November 2026 · Docs: https://ui.j4m5.com · Registry: https://ui.j4m5.com/r/{name}.json
> Built on shadcn/ui + Tailwind CSS v4. This file is the single source of truth for AI agents building J4M5 UI.
> Read all of it before writing code. When in doubt, follow the **Rules** section literally.
## 1. Identity in one paragraph
J4M5 is **print meets resin**: matte, risograph-printed surfaces under clear acrylic. Content sits on matte "paper" with fine grain and a halftone second-ink offset. Floating chrome (navigation, tab bars, popovers, dialogs, toasts) is translucent glass. Around 90% of every view uses **mineral** neutrals (muted, low-chroma tones from every hue, never pure white). At most 10% uses one rich **gem** accent. **Figtree** is the predominant typeface. **Fraunces** (soft serif) is for display moments, and **Zilla Slab** is for stamp-like labels. Shapes are **organic**: asymmetric radii, seeded blobs and slightly tilted stickers, laid on a grid that still aligns.
## 2. Rules (MUST / SHOULD / NEVER)
### MUST
- MUST use semantic tokens (`bg-background`, `text-foreground`, `bg-card`, `bg-primary`, …) or J4M5 tokens (`bg-gem-*`, `bg-mineral-*`, `rounded-card`, …). Never hard-code hex values in components.
- MUST put readable content on **matte** surfaces (`riso-print`, `riso-flat`, or `Card`).
- MUST make floating or overlapping chrome **acrylic** (`glass`, `glass-strong`, `GlassPanel`, `Tabs` list, `Dialog`).
- MUST have printed content or art beneath any glass element so there is something to refract.
- MUST use Figtree (`font-sans`) for all UI, body text, form controls, tables and most headings.
- MUST keep one dominant gem per view. A second gem may appear only as an overprint, illustration or small sticker.
- MUST meet WCAG AA. Use the pairs in §5.4: gem washes take the `-deep` text of the same gem, and solid gems take `text-on-gem` (or `text-on-bright` for topaz).
- MUST support light and dark (`.dark` class on ``), `prefers-reduced-motion` and `prefers-reduced-transparency`.
- MUST give every interactive element a visible focus ring (`focus-visible:ring-[3px] focus-visible:ring-ring/50`).
### SHOULD
- SHOULD use `Card` (variant `print`) for primary content blocks, `variant="flat"` inside lists or nested cards, and `variant="glass"` only when the card overlaps other content.
- SHOULD express elevation through **material** (paper → print → overprint → acrylic → gem), not bigger shadows.
- SHOULD use `Blob` (seeded) for decorative shapes and image masks, and overlap two blobs with `overprint` so a third color forms.
- SHOULD vary corner radii by using the shape tokens, never a single uniform radius.
- SHOULD limit Fraunces to 32px and up, once or twice per screen (hero, section opener, dialog title, pull quote).
- SHOULD use Zilla Slab (`font-slab`) uppercase with tracking `0.08em` for eyebrows, stickers, tickets and data labels at 11–15px.
- SHOULD keep running text to 60–70 characters per line, use `text-balance` on headings, and use `tabular-nums` for data.
- SHOULD use a mobile-first layout, with a glass bottom tab bar on phones and a glass pill header on larger screens.
### NEVER
- NEVER use `#FFFFFF` or `bg-white`. The lightest surface is Paper (`--paper`, #efeee9).
- NEVER stack glass on glass, and never set long body copy directly on glass.
- NEVER use large, blurry drop shadows on content. The offset is a crisp second-ink halftone or solid offset.
- NEVER use perfect circles for containers or the same radius on all four corners of a card.
- NEVER rotate body text, inputs or buttons. Only stickers are tilted (±2–3°).
- NEVER put `overflow: hidden` on an element with `riso-print`, because it clips the offset. Wrap it instead.
- NEVER use more than one primary button per view.
- NEVER use Fraunces or Zilla Slab inside form controls or for paragraphs.
- NEVER use neon or fully saturated colors outside the gem set, and never use purple-to-blue gradients.
## 3. Install (shadcn/ui registry)
Requires Tailwind CSS v4 and a project that has already run `npx shadcn@latest init`.
```bash
# Everything: theme + fonts + all components (overwrites stock shadcn tokens)
npx shadcn@latest add https://ui.j4m5.com/r/j4m5-kit.json
# Theme + fonts only
npx shadcn@latest add https://ui.j4m5.com/r/j4m5.json
# Single component
npx shadcn@latest add https://ui.j4m5.com/r/card.json
```
Optional namespace in `components.json`:
```json
{ "registries": { "@j4m5": "https://ui.j4m5.com/r/{name}.json" } }
```
Then run `npx shadcn add @j4m5/button`.
| Item | Type | Notes |
|---|---|---|
| `j4m5` | style | Tokens (light + dark), `@theme inline` mappings, riso/glass utilities, base styles. Depends on `utils` + the three fonts. |
| `font-figtree` | font | `--font-sans`. next/font (Next.js) or `@fontsource-variable/figtree`. |
| `font-fraunces` | font | `--font-display`. For the SOFT axis outside Next.js, also import `@fontsource-variable/fraunces/full.css`. With next/font, pass `axes: ["SOFT", "WONK", "opsz"]`. |
| `font-zilla-slab` | font | `--font-slab`, weights 500/600/700. |
| `organic` | lib | `seeded()`, `blobPath()`, `inkStyle()`, `GEMS`. |
| `button` `card` `badge` `input` `textarea` `label` `switch` `tabs` `dialog` `alert` | ui | Same names as shadcn, so they replace the stock files. |
| `glass-panel` `riso-surface` `blob` `sticker` | ui | New J4M5 primitives. |
| `j4m5-kit` | style | Bundle of all of the above. |
## 4. Materials and depth
| Level | Name | Use for | Implementation |
|---|---|---|---|
| 0 | Paper | Page background | `body` has `bg-background` + grain (`--grain`) |
| 1 | Print | Cards, sheets, list rows, inputs | `riso-print` (offset) or `riso-flat` with `--surface` |
| 2 | Overprint | Illustration, emphasis, hero art | Gem fills + `overprint` (multiply in light, screen in dark) |
| 3 | Acrylic | Nav, tab bar, popover, dialog, toast, HUD | `glass` / `glass-strong` |
| 4 | Gem | Primary CTA, active state, sticker | Solid `bg-gem-*` or `bg-primary` |
### Utilities (Tailwind v4 `@utility`, shipped by the `j4m5` style)
| Class | Effect | Knobs |
|---|---|---|
| `riso-print` | Matte fill + grain via `::after`. Halftone dot offset via `::before` (translated `--offset-x/y`) | `--surface` (fill), `--overprint` (dot ink), `--halftone-size` |
| `riso-flat` | Matte fill + grain, no offset | `--surface` |
| `riso-halftone` | Dot screen background | `--dot`, `--halftone-size` |
| `riso-misreg` | Misregistered text shadow (0.045em) | `--misreg` |
| `overprint` | `mix-blend-mode: var(--overprint-blend)` | — |
| `glass` | Translucent fill, 18px backdrop blur + saturate, sheen gradient, 1px light border, hairline edge, soft shadow | `--glass`, `--glass-blur` |
| `glass-strong` | Denser glass for dialogs and toasts | `--glass-strong` |
| `tilt-l` / `tilt-r` | −2.5° / +2° rotation (stickers only) | — |
Re-ink a surface: `style={{ "--overprint": "var(--gem-ruby-light)" }}`, or use the `ink="ruby"` prop on `Card` / `RisoSurface`.
Set a fill: `className="riso-flat [--surface:var(--mineral-sage-100)]"`, or ``.
## 5. Color
### 5.1 Minerals (muted neutrals; light-mode values)
Steps carry a **role** that holds in both modes, and lightness inverts in dark mode:
`100` = quiet wash / surface · `300` = secondary fill, illustration · `500` = disabled, hairline art · `700` = strong text / dark fill.
| Mineral | Character | 100 | 300 | 500 | 700 |
|---|---|---|---|---|---|
| chalk | true neutral | `#e9e8e4` | `#c6c4bf` | `#94928d` | `#57554f` |
| stone | warm grey | `#ede7df` | `#cbc3b9` | `#9a9187` | `#5e5347` |
| clay | terracotta | `#f7e3dc` | `#d7beb5` | `#a68b82` | `#6c4d42` |
| rose | dusty pink | `#f5e2e5` | `#d5bdc0` | `#a48b8e` | `#694c50` |
| sand | ochre | `#efe7d6` | `#cdc3ae` | `#9c917a` | `#615438` |
| moss | olive | `#e5ebd9` | `#c1c7b1` | `#8f967e` | `#52593c` |
| sage | green-grey | `#ddece3` | `#b6cabe` | `#83988c` | `#425c4e` |
| fog | sea grey | `#dcebf0` | `#b5c8ce` | `#82969d` | `#415a62` |
| slate | blue-grey | `#e0e8f6` | `#bbc5d6` | `#8893a5` | `#49566b` |
| heather | violet-grey | `#ece4f3` | `#c9c0d2` | `#988da0` | `#5c4f66` |
Tailwind: `bg-mineral-sage-100`, `text-mineral-slate-700`, etc. CSS: `var(--mineral-sage-100)`.
### 5.2 Gems (rich accents)
`light` = wash (badge/alert background) · `base` = solid fill · `deep` = text on the wash · `glow` = bright variant used for dark-mode accents.
In dark mode `-light` becomes a dark wash and `-deep` becomes light text, so the pair still works.
| Gem | Role | ≈ Riso ink | light | base | deep | glow | base (oklch) |
|---|---|---|---|---|---|---|---|
| sapphire | primary, links, focus, info | Medium Blue | `#98b2e0` | `#2151af` | `#06296f` | `#5483dc` | `oklch(0.46 0.16 262)` |
| ruby | destructive, hot, love | Crimson | `#f2b0b4` | `#b52f48` | `#770f27` | `#e66b79` | `oklch(0.52 0.17 15)` |
| emerald | success, publish | Green | `#aad3bb` | `#008053` | `#005032` | `#58b084` | `oklch(0.53 0.12 160)` |
| topaz | warning, highlight, stickers | Sunflower | `#f9d8b1` | `#e19b34` | `#7d5000` | `#ffc57b` | `oklch(0.74 0.14 72)` |
| amethyst | new, premium, creative | Purple | `#c4b0de` | `#7544a3` | `#472268` | `#a278d1` | `oklch(0.49 0.15 305)` |
| tourmaline | info alt, calm data | Teal | `#a0cbca` | `#007575` | `#004747` | `#46a7a6` | `oklch(0.51 0.1 195)` |
Tailwind: `bg-gem-ruby`, `bg-gem-ruby-light`, `text-gem-ruby-deep`, `bg-gem-ruby-glow`.
### 5.3 Core + semantic tokens (shadcn variables)
| Token | Light | Dark |
|---|---|---|
| `--background` | `oklch(0.948 0.006 90)` | `oklch(0.195 0.012 265)` |
| `--foreground` | `oklch(0.25 0.02 265)` | `oklch(0.93 0.008 90)` |
| `--card` | `oklch(0.918 0.01 84)` | `oklch(0.235 0.014 265)` |
| `--card-foreground` | `oklch(0.25 0.02 265)` | `oklch(0.93 0.008 90)` |
| `--popover` | `oklch(0.97 0.005 90 / 0.72)` | `oklch(0.27 0.016 265 / 0.62)` |
| `--primary` | `oklch(0.46 0.16 262)` | `oklch(0.7 0.12 262)` |
| `--primary-foreground` | `oklch(0.948 0.006 90)` | `oklch(0.195 0.012 265)` |
| `--secondary` | `oklch(0.885 0.014 80)` | `oklch(0.29 0.015 265)` |
| `--muted` | `oklch(0.905 0.01 85)` | `oklch(0.27 0.014 265)` |
| `--muted-foreground` | `oklch(0.47 0.018 265)` | `oklch(0.72 0.012 265)` |
| `--accent` | `oklch(0.9 0.028 262)` | `oklch(0.32 0.045 262)` |
| `--accent-foreground` | `oklch(0.31 0.128 262)` | `oklch(0.88 0.04 262)` |
| `--destructive` | `oklch(0.52 0.17 15)` | `oklch(0.68 0.153 15)` |
| `--border` | `oklch(0.25 0.02 265 / 0.14)` | `oklch(0.93 0.008 90 / 0.12)` |
| `--input` | `oklch(0.25 0.02 265 / 0.2)` | `oklch(0.93 0.008 90 / 0.18)` |
| `--ring` | `oklch(0.62 0.144 262)` | `oklch(0.7 0.12 262)` |
| `--chart-1` | `oklch(0.46 0.16 262)` | `oklch(0.7 0.12 262)` |
| `--chart-2` | `oklch(0.74 0.14 72)` | `oklch(0.86 0.126 72)` |
| `--chart-3` | `oklch(0.53 0.12 160)` | `oklch(0.69 0.108 160)` |
| `--chart-4` | `oklch(0.52 0.17 15)` | `oklch(0.68 0.153 15)` |
| `--chart-5` | `oklch(0.49 0.15 305)` | `oklch(0.65 0.135 305)` |
| `--overprint` | `oklch(0.76 0.072 262)` | `oklch(0.31 0.128 262)` |
| `--glass` | `oklch(0.98 0.004 90 / 0.58)` | `oklch(0.3 0.016 265 / 0.5)` |
Extra J4M5 variables: `--paper`, `--ink`, `--on-gem` (text on solid gems, both modes), `--on-bright` (text on topaz), `--overprint`, `--overprint-blend`, `--grain`, `--glass`, `--glass-strong`, `--glass-border`, `--glass-edge`, `--glass-highlight`, `--glass-sheen`, `--glass-shadow`, `--glass-blur`, `--success`, `--warning`, `--info`, `--offset-x` (7px), `--offset-y` (8px), `--halftone-size` (5px).
### 5.4 Approved contrast pairs (WCAG AA)
| Text | Background | Ratio (light) |
|---|---|---|
| `foreground` | `background` | 13.8 |
| `muted-foreground` | `background` | 5.9 |
| `primary-foreground` | `primary` | 6.3 |
| `gem-X-deep` | `gem-X-light` | ≥ 5.1 (topaz 5.2, ruby 6.2) |
| `on-gem` | `gem-sapphire/ruby/emerald/tourmaline/amethyst` | ≥ 4.5 |
| `on-bright` | `gem-topaz` | 6.8 |
### 5.5 Proportion and sample palettes
Use the 60 · 22 · 10 · 6 · 2 rule: base neutral, secondary neutral, ink, dominant gem, accent gem.
| Palette | Use | 60% base | 22% secondary | 10% ink | 6% gem | 2% accent |
|---|---|---|---|---|---|---|
| Harbor at Dusk | product UI, docs | `#efeee9` | `#b5c8ce` | `#49566b` | `#2151af` | `#e19b34` |
| Orchard | kids, learning, outdoors | `#efe7d6` | `#c1c7b1` | `#52593c` | `#008053` | `#b52f48` |
| Clay Studio | portfolio, editorial | `#ede7df` | `#d7beb5` | `#6c4d42` | `#007575` | `#f9d8b1` |
| Field Notes | dashboards, tools | `#e9e8e4` | `#b6cabe` | `#1d222b` | `#007575` | `#e19b34` |
| Gallery Night | dark mode, media | `#12151a` | `#5c4f66` | `#eae8e2` | `#a278d1` | `#ffc57b` |
| Velvet Arcade | games, dark | `#1d2027` | `#49566b` | `#e66b79` | `#5483dc` | `#58b084` |
## 6. Typography
| Role | Font | Size / line | Weight | Tracking | Tailwind |
|---|---|---|---|---|---|
| display-xl | Fraunces (SOFT 100, WONK 0) | 72/72 | 600 | −0.015em | `font-display text-7xl font-semibold` |
| display | Fraunces | 48/52 | 600 | −0.015em | `font-display text-5xl font-semibold` |
| h1 | Figtree | 40/44 | 800 | −0.025em | `text-4xl font-extrabold tracking-[-0.025em]` |
| h2 | Figtree | 28/34 | 750 | −0.015em | `text-[28px] font-[750]` |
| h3 | Figtree | 20/28 | 700 | 0 | `text-xl font-bold` |
| body-lg | Figtree | 18/28 | 400 | 0 | `text-lg` |
| body | Figtree | 16/26 | 400 | 0 | `text-base` |
| small | Figtree | 14/20 | 500 | 0 | `text-sm font-medium` |
| label | Zilla Slab | 13 | 600 | +0.08em, uppercase | `font-slab text-[13px] font-semibold uppercase tracking-[0.08em]` |
Fraunces settings: `font-variation-settings: "SOFT" 100, "WONK" 0;`. Display lines may add `riso-misreg`.
## 7. Shape
| Token | Value | Tailwind | Use |
|---|---|---|---|
| `--shape-card` | `26px 34px 30px 22px / 30px 24px 34px 28px` | `rounded-card` | Cards, sheets, dialogs |
| `--shape-tile` | `18px 24px 20px 26px / 22px 18px 26px 20px` | `rounded-tile` | Alerts, rows, thumbnails |
| `--shape-control` | `14px 18px 16px 20px / 16px 14px 20px 18px` | `rounded-control` | Inputs, selects, code |
| `--shape-pill` | `2rem 2.4rem 2.2rem 2.6rem / 2.4rem 2.2rem 2.6rem 2.2rem` | `rounded-pill` | Buttons, badges, tabs, nav |
| `--shape-pebble` | `42% 58% 55% 45% / 52% 44% 56% 48%` | `rounded-pebble` | Icon buttons, avatars, switch thumb |
| `--shape-river` | `64% 36% 48% 52% / 38% 58% 42% 62%` | `rounded-river` | Image masks, hero art |
| `--shape-seed` | `60% 40% 42% 58% / 62% 56% 44% 38%` | `rounded-seed` | Stickers, stamps |
`Blob` props: `seed` (int, deterministic), `points` (5–9), `wobble` (0.08 near-round · 0.2 pebble · 0.32 default · 0.45 lively · 0.6 splash), `fill` (CSS color), `overprint`, `halftone`.
## 8. Components (API cheat sheet)
```tsx
import { Button } from "@/components/ui/button"
// variant: default | secondary | gem | glass | outline | ghost | destructive | link
// size: default | sm | lg | icon | icon-sm | icon-lg
import { Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter } from "@/components/ui/card"
// variant: print (default) | flat | glass ; ink: sapphire | ruby | emerald | topaz | amethyst | tourmaline
Builds…
import { Badge } from "@/components/ui/badge"
// variant: default | secondary | outline | destructive | glass | sapphire | ruby | emerald | topaz | amethyst | tourmaline
Live
import { Input } from "@/components/ui/input" // matte well, rounded-control
import { Textarea } from "@/components/ui/textarea" // matte well, rounded-card
import { Label } from "@/components/ui/label"
import { Switch } from "@/components/ui/switch" // matte track + glass pebble thumb
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs" // glass rail, printed active chip
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog" // glass-strong sheet, Fraunces title
import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert"
// Alert variant: default | info | success | warning | destructive (gem washes)
import { GlassPanel } from "@/components/ui/glass-panel"
// intensity: soft | strong ; shape: card | pill | tile | pebble
…
import { RisoSurface } from "@/components/ui/riso-surface"
// variant: print | flat | halftone ; shape: card | tile | pebble | river | seed | none ; ink: Gem ; tone: CSS color
…
import { Blob } from "@/components/ui/blob"
import { Sticker } from "@/components/ui/sticker"
// tone: topaz | ruby | emerald | sapphire | amethyst | tourmaline | paper ; tilt: left | right | none
Sold out
```
## 9. Patterns
**App shell (mobile-first)**
```tsx
…print cards…
```
**Hero**: Fraunces headline with `riso-misreg`, Figtree lede, one primary `Button` and one `glass` button, and two overlapping `Blob`s (one with `overprint`, optionally a third with `halftone`) set behind the copy, `aria-hidden`.
**List of items**: Wrap in one `Card` (print) and use `riso-flat` rows inside with `rounded-tile`. Don't put halftone offsets on every row.
**Data viz**: Mineral bars or lines. Use one gem only for the highlighted series or value, and use `chart-1…5` for multi-series charts.
**Empty state**: `Blob` with `halftone` + Figtree h3 + one-sentence explanation + one primary button.
**Forms**: Labels above inputs, helper text in `text-muted-foreground text-sm`, and errors in `text-destructive` with `aria-invalid` on the input. Error text says what went wrong and how to fix it.
## 10. Dark mode
- Paper becomes Carbon `#12151a`, Ink becomes Bone `#eae8e2`, and primary becomes sapphire glow.
- Mineral steps and gem washes invert automatically (role-preserving), so use the same classes in both modes.
- Overprint blend switches to `screen`, and the grain switches to light specks.
- Glass becomes a dark translucent fill with a faint white sheen.
## 11. Voice and microcopy
Use plain, specific and active language. A button says exactly what happens ("Publish build", not "Submit"). Error messages say what went wrong and how to fix it. Avoid jargon unless the audience uses it.
## 12. Pre-flight checklist (run before returning code)
- [ ] No `#fff`, `bg-white` or hard-coded hex values in components
- [ ] Content on matte, chrome on glass, no glass on glass
- [ ] One dominant gem; everything else mineral or semantic
- [ ] Figtree everywhere except display (Fraunces) and stamps (Zilla Slab)
- [ ] Shape tokens used and no uniform radius on cards; only stickers rotated
- [ ] Contrast pairs from §5.4; focus rings visible; reduced motion and transparency respected
- [ ] Works in light and dark and at 360px wide
## License
Code, tokens and docs are MIT licensed (© 2026 J4M5). Components are adapted from shadcn/ui, which is also MIT. Keep both notices when you redistribute. Fonts are not covered: Figtree, Fraunces and Zilla Slab use the SIL Open Font License 1.1. Full text: https://ui.j4m5.com/LICENSE.txt
## Sources
- [shadcn/ui: registry-item.json spec (cssVars, css, fonts, docs)](https://ui.shadcn.com/docs/registry/registry-item-json)
- [shadcn/ui: registry item JSON schema](https://ui.shadcn.com/schema/registry-item.json)
- [Tailwind CSS v4: adding custom styles (@utility with nesting)](https://tailwindcss.com/docs/adding-custom-styles)
- [Tailwind CSS v4: functions and directives (@theme, @utility, @custom-variant)](https://tailwindcss.com/docs/functions-and-directives)
- [Figtree on Google Fonts](https://fonts.google.com/specimen/Figtree)
- [Fraunces on Google Fonts: the wght, opsz, SOFT and WONK axes](https://fonts.google.com/specimen/Fraunces/about)
- [Fraunces on Fontsource (full axis build)](https://fontsource.org/fonts/fraunces/about)
- [Zilla Slab on Google Fonts](https://fonts.google.com/specimen/Zilla+Slab)
- [Riso ink color reference (hex values for Riso drum inks)](https://rdrr.io/github/anfederico/risoinks/src/R/color.R)
- [MICA: Riso image making and printing (overprinting inks)](https://www.mica.edu/maker-spaces-studios/2d-prototyping-studio/riso-image-making-and-printing/)
- [WCAG 2.1: contrast (minimum), 1.4.3](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html)
- [Lucide icons](https://lucide.dev)
## Appendix A. Full CSS variables
```css
:root {
--radius: 1rem;
--shape-pebble: 42% 58% 55% 45% / 52% 44% 56% 48%;
--shape-river: 64% 36% 48% 52% / 38% 58% 42% 62%;
--shape-seed: 60% 40% 42% 58% / 62% 56% 44% 38%;
--shape-card: 26px 34px 30px 22px / 30px 24px 34px 28px;
--shape-tile: 18px 24px 20px 26px / 22px 18px 26px 20px;
--shape-control: 14px 18px 16px 20px / 16px 14px 20px 18px;
--shape-pill: 2rem 2.4rem 2.2rem 2.6rem / 2.4rem 2.2rem 2.6rem 2.2rem;
--offset-x: 7px;
--offset-y: 8px;
--halftone-size: 5px;
--glass-blur: 18px;
--gem-ruby-light: oklch(0.82 0.077 15);
--gem-ruby: oklch(0.52 0.17 15);
--gem-ruby-deep: oklch(0.37 0.136 15);
--gem-ruby-glow: oklch(0.68 0.153 15);
--gem-topaz-light: oklch(0.9 0.063 72);
--gem-topaz: oklch(0.74 0.14 72);
--gem-topaz-deep: oklch(0.47 0.112 72);
--gem-topaz-glow: oklch(0.86 0.126 72);
--gem-emerald-light: oklch(0.83 0.054 160);
--gem-emerald: oklch(0.53 0.12 160);
--gem-emerald-deep: oklch(0.38 0.096 160);
--gem-emerald-glow: oklch(0.69 0.108 160);
--gem-tourmaline-light: oklch(0.81 0.045 195);
--gem-tourmaline: oklch(0.51 0.1 195);
--gem-tourmaline-deep: oklch(0.36 0.08 195);
--gem-tourmaline-glow: oklch(0.67 0.09 195);
--gem-sapphire-light: oklch(0.76 0.072 262);
--gem-sapphire: oklch(0.46 0.16 262);
--gem-sapphire-deep: oklch(0.31 0.128 262);
--gem-sapphire-glow: oklch(0.62 0.144 262);
--gem-amethyst-light: oklch(0.79 0.068 305);
--gem-amethyst: oklch(0.49 0.15 305);
--gem-amethyst-deep: oklch(0.34 0.12 305);
--gem-amethyst-glow: oklch(0.65 0.135 305);
--mineral-chalk-100: oklch(0.93 0.006 90);
--mineral-chalk-300: oklch(0.82 0.007 90);
--mineral-chalk-500: oklch(0.66 0.008 90);
--mineral-chalk-700: oklch(0.45 0.01 90);
--mineral-stone-100: oklch(0.93 0.013 70);
--mineral-stone-300: oklch(0.82 0.016 70);
--mineral-stone-500: oklch(0.66 0.018 70);
--mineral-stone-700: oklch(0.45 0.023 70);
--mineral-clay-100: oklch(0.93 0.025 40);
--mineral-clay-300: oklch(0.82 0.032 40);
--mineral-clay-500: oklch(0.66 0.035 40);
--mineral-clay-700: oklch(0.45 0.046 40);
--mineral-rose-100: oklch(0.93 0.021 10);
--mineral-rose-300: oklch(0.82 0.027 10);
--mineral-rose-500: oklch(0.66 0.03 10);
--mineral-rose-700: oklch(0.45 0.039 10);
--mineral-sand-100: oklch(0.93 0.025 85);
--mineral-sand-300: oklch(0.82 0.032 85);
--mineral-sand-500: oklch(0.66 0.035 85);
--mineral-sand-700: oklch(0.45 0.046 85);
--mineral-moss-100: oklch(0.93 0.025 120);
--mineral-moss-300: oklch(0.82 0.032 120);
--mineral-moss-500: oklch(0.66 0.035 120);
--mineral-moss-700: oklch(0.45 0.046 120);
--mineral-sage-100: oklch(0.93 0.021 160);
--mineral-sage-300: oklch(0.82 0.027 160);
--mineral-sage-500: oklch(0.66 0.03 160);
--mineral-sage-700: oklch(0.45 0.039 160);
--mineral-fog-100: oklch(0.93 0.017 220);
--mineral-fog-300: oklch(0.82 0.023 220);
--mineral-fog-500: oklch(0.66 0.025 220);
--mineral-fog-700: oklch(0.45 0.033 220);
--mineral-slate-100: oklch(0.93 0.021 262);
--mineral-slate-300: oklch(0.82 0.027 262);
--mineral-slate-500: oklch(0.66 0.03 262);
--mineral-slate-700: oklch(0.45 0.039 262);
--mineral-heather-100: oklch(0.93 0.021 310);
--mineral-heather-300: oklch(0.82 0.027 310);
--mineral-heather-500: oklch(0.66 0.03 310);
--mineral-heather-700: oklch(0.45 0.039 310);
--background: oklch(0.948 0.006 90);
--foreground: oklch(0.25 0.02 265);
--card: oklch(0.918 0.01 84);
--card-foreground: oklch(0.25 0.02 265);
--popover: oklch(0.97 0.005 90 / 0.72);
--popover-foreground: oklch(0.25 0.02 265);
--primary: oklch(0.46 0.16 262);
--primary-foreground: oklch(0.948 0.006 90);
--secondary: oklch(0.885 0.014 80);
--secondary-foreground: oklch(0.25 0.02 265);
--muted: oklch(0.905 0.01 85);
--muted-foreground: oklch(0.47 0.018 265);
--accent: oklch(0.9 0.028 262);
--accent-foreground: oklch(0.31 0.128 262);
--destructive: oklch(0.52 0.17 15);
--destructive-foreground: oklch(0.948 0.006 90);
--border: oklch(0.25 0.02 265 / 0.14);
--input: oklch(0.25 0.02 265 / 0.2);
--ring: oklch(0.62 0.144 262);
--chart-1: oklch(0.46 0.16 262);
--chart-2: oklch(0.74 0.14 72);
--chart-3: oklch(0.53 0.12 160);
--chart-4: oklch(0.52 0.17 15);
--chart-5: oklch(0.49 0.15 305);
--sidebar: oklch(0.93 0.008 85);
--sidebar-foreground: oklch(0.25 0.02 265);
--sidebar-primary: oklch(0.46 0.16 262);
--sidebar-primary-foreground: oklch(0.948 0.006 90);
--sidebar-accent: oklch(0.9 0.028 262);
--sidebar-accent-foreground: oklch(0.31 0.128 262);
--sidebar-border: oklch(0.25 0.02 265 / 0.12);
--sidebar-ring: oklch(0.62 0.144 262);
--paper: oklch(0.948 0.006 90);
--ink: oklch(0.25 0.02 265);
--overprint: oklch(0.76 0.072 262);
--overprint-blend: multiply;
--glass: oklch(0.98 0.004 90 / 0.58);
--glass-strong: oklch(0.98 0.004 90 / 0.78);
--glass-border: oklch(1 0 0 / 0.65);
--glass-edge: oklch(0.25 0.02 265 / 0.10);
--glass-highlight: oklch(1 0 0 / 0.85);
--glass-shadow: 0 1px 2px oklch(0.25 0.02 265 / 0.06), 0 12px 32px -8px oklch(0.25 0.02 265 / 0.22);
--success: oklch(0.53 0.12 160);
--warning: oklch(0.47 0.112 72);
--info: oklch(0.51 0.1 195);
--on-gem: oklch(0.97 0.005 90);
--on-bright: oklch(0.25 0.02 265);
--grain: url("data:image/svg+xml;utf8,");
--glass-sheen: oklch(1 0 0 / 0.42);
--font-sans: 'Figtree', ui-sans-serif, system-ui, sans-serif;
--font-display: 'Fraunces', ui-serif, Georgia, serif;
--font-slab: 'Zilla Slab', ui-serif, Georgia, serif;
--font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
color-scheme: dark;
--background: oklch(0.195 0.012 265);
--foreground: oklch(0.93 0.008 90);
--card: oklch(0.235 0.014 265);
--card-foreground: oklch(0.93 0.008 90);
--popover: oklch(0.27 0.016 265 / 0.62);
--popover-foreground: oklch(0.93 0.008 90);
--primary: oklch(0.7 0.12 262);
--primary-foreground: oklch(0.195 0.012 265);
--secondary: oklch(0.29 0.015 265);
--secondary-foreground: oklch(0.93 0.008 90);
--muted: oklch(0.27 0.014 265);
--muted-foreground: oklch(0.72 0.012 265);
--accent: oklch(0.32 0.045 262);
--accent-foreground: oklch(0.88 0.04 262);
--destructive: oklch(0.68 0.153 15);
--destructive-foreground: oklch(0.195 0.012 265);
--border: oklch(0.93 0.008 90 / 0.12);
--input: oklch(0.93 0.008 90 / 0.18);
--ring: oklch(0.7 0.12 262);
--chart-1: oklch(0.7 0.12 262);
--chart-2: oklch(0.86 0.126 72);
--chart-3: oklch(0.69 0.108 160);
--chart-4: oklch(0.68 0.153 15);
--chart-5: oklch(0.65 0.135 305);
--sidebar: oklch(0.215 0.013 265);
--sidebar-foreground: oklch(0.93 0.008 90);
--sidebar-primary: oklch(0.7 0.12 262);
--sidebar-primary-foreground: oklch(0.195 0.012 265);
--sidebar-accent: oklch(0.32 0.045 262);
--sidebar-accent-foreground: oklch(0.88 0.04 262);
--sidebar-border: oklch(0.93 0.008 90 / 0.1);
--sidebar-ring: oklch(0.7 0.12 262);
--paper: oklch(0.195 0.012 265);
--ink: oklch(0.93 0.008 90);
--overprint: oklch(0.31 0.128 262);
--overprint-blend: screen;
--glass: oklch(0.3 0.016 265 / 0.5);
--glass-strong: oklch(0.3 0.016 265 / 0.72);
--glass-border: oklch(1 0 0 / 0.14);
--glass-edge: oklch(0 0 0 / 0.35);
--glass-highlight: oklch(1 0 0 / 0.18);
--glass-shadow: 0 1px 2px oklch(0 0 0 / 0.3), 0 16px 40px -10px oklch(0 0 0 / 0.6);
--success: oklch(0.69 0.108 160);
--warning: oklch(0.86 0.126 72);
--info: oklch(0.67 0.09 195);
--mineral-chalk-100: oklch(0.27 0.006 90);
--mineral-chalk-300: oklch(0.36 0.006 90);
--mineral-chalk-500: oklch(0.55 0.008 90);
--mineral-chalk-700: oklch(0.82 0.008 90);
--mineral-stone-100: oklch(0.27 0.014 70);
--mineral-stone-300: oklch(0.36 0.014 70);
--mineral-stone-500: oklch(0.55 0.018 70);
--mineral-stone-700: oklch(0.82 0.018 70);
--mineral-clay-100: oklch(0.27 0.028 40);
--mineral-clay-300: oklch(0.36 0.028 40);
--mineral-clay-500: oklch(0.55 0.035 40);
--mineral-clay-700: oklch(0.82 0.035 40);
--mineral-rose-100: oklch(0.27 0.024 10);
--mineral-rose-300: oklch(0.36 0.024 10);
--mineral-rose-500: oklch(0.55 0.03 10);
--mineral-rose-700: oklch(0.82 0.03 10);
--mineral-sand-100: oklch(0.27 0.028 85);
--mineral-sand-300: oklch(0.36 0.028 85);
--mineral-sand-500: oklch(0.55 0.035 85);
--mineral-sand-700: oklch(0.82 0.035 85);
--mineral-moss-100: oklch(0.27 0.028 120);
--mineral-moss-300: oklch(0.36 0.028 120);
--mineral-moss-500: oklch(0.55 0.035 120);
--mineral-moss-700: oklch(0.82 0.035 120);
--mineral-sage-100: oklch(0.27 0.024 160);
--mineral-sage-300: oklch(0.36 0.024 160);
--mineral-sage-500: oklch(0.55 0.03 160);
--mineral-sage-700: oklch(0.82 0.03 160);
--mineral-fog-100: oklch(0.27 0.02 220);
--mineral-fog-300: oklch(0.36 0.02 220);
--mineral-fog-500: oklch(0.55 0.025 220);
--mineral-fog-700: oklch(0.82 0.025 220);
--mineral-slate-100: oklch(0.27 0.024 262);
--mineral-slate-300: oklch(0.36 0.024 262);
--mineral-slate-500: oklch(0.55 0.03 262);
--mineral-slate-700: oklch(0.82 0.03 262);
--mineral-heather-100: oklch(0.27 0.024 310);
--mineral-heather-300: oklch(0.36 0.024 310);
--mineral-heather-500: oklch(0.55 0.03 310);
--mineral-heather-700: oklch(0.82 0.03 310);
--gem-ruby-light: oklch(0.34 0.071 15);
--gem-ruby-deep: oklch(0.88 0.071 15);
--gem-topaz-light: oklch(0.34 0.059 72);
--gem-topaz-deep: oklch(0.88 0.059 72);
--gem-emerald-light: oklch(0.34 0.05 160);
--gem-emerald-deep: oklch(0.88 0.05 160);
--gem-tourmaline-light: oklch(0.34 0.042 195);
--gem-tourmaline-deep: oklch(0.88 0.042 195);
--gem-sapphire-light: oklch(0.34 0.067 262);
--gem-sapphire-deep: oklch(0.88 0.067 262);
--gem-amethyst-light: oklch(0.34 0.063 305);
--gem-amethyst-deep: oklch(0.88 0.063 305);
--on-gem: oklch(0.97 0.005 90);
--on-bright: oklch(0.25 0.02 265);
--grain: url("data:image/svg+xml;utf8,");
--glass-sheen: oklch(1 0 0 / 0.07);
}
}
:root[data-theme="dark"] {
color-scheme: dark;
--background: oklch(0.195 0.012 265);
--foreground: oklch(0.93 0.008 90);
--card: oklch(0.235 0.014 265);
--card-foreground: oklch(0.93 0.008 90);
--popover: oklch(0.27 0.016 265 / 0.62);
--popover-foreground: oklch(0.93 0.008 90);
--primary: oklch(0.7 0.12 262);
--primary-foreground: oklch(0.195 0.012 265);
--secondary: oklch(0.29 0.015 265);
--secondary-foreground: oklch(0.93 0.008 90);
--muted: oklch(0.27 0.014 265);
--muted-foreground: oklch(0.72 0.012 265);
--accent: oklch(0.32 0.045 262);
--accent-foreground: oklch(0.88 0.04 262);
--destructive: oklch(0.68 0.153 15);
--destructive-foreground: oklch(0.195 0.012 265);
--border: oklch(0.93 0.008 90 / 0.12);
--input: oklch(0.93 0.008 90 / 0.18);
--ring: oklch(0.7 0.12 262);
--chart-1: oklch(0.7 0.12 262);
--chart-2: oklch(0.86 0.126 72);
--chart-3: oklch(0.69 0.108 160);
--chart-4: oklch(0.68 0.153 15);
--chart-5: oklch(0.65 0.135 305);
--sidebar: oklch(0.215 0.013 265);
--sidebar-foreground: oklch(0.93 0.008 90);
--sidebar-primary: oklch(0.7 0.12 262);
--sidebar-primary-foreground: oklch(0.195 0.012 265);
--sidebar-accent: oklch(0.32 0.045 262);
--sidebar-accent-foreground: oklch(0.88 0.04 262);
--sidebar-border: oklch(0.93 0.008 90 / 0.1);
--sidebar-ring: oklch(0.7 0.12 262);
--paper: oklch(0.195 0.012 265);
--ink: oklch(0.93 0.008 90);
--overprint: oklch(0.31 0.128 262);
--overprint-blend: screen;
--glass: oklch(0.3 0.016 265 / 0.5);
--glass-strong: oklch(0.3 0.016 265 / 0.72);
--glass-border: oklch(1 0 0 / 0.14);
--glass-edge: oklch(0 0 0 / 0.35);
--glass-highlight: oklch(1 0 0 / 0.18);
--glass-shadow: 0 1px 2px oklch(0 0 0 / 0.3), 0 16px 40px -10px oklch(0 0 0 / 0.6);
--success: oklch(0.69 0.108 160);
--warning: oklch(0.86 0.126 72);
--info: oklch(0.67 0.09 195);
--mineral-chalk-100: oklch(0.27 0.006 90);
--mineral-chalk-300: oklch(0.36 0.006 90);
--mineral-chalk-500: oklch(0.55 0.008 90);
--mineral-chalk-700: oklch(0.82 0.008 90);
--mineral-stone-100: oklch(0.27 0.014 70);
--mineral-stone-300: oklch(0.36 0.014 70);
--mineral-stone-500: oklch(0.55 0.018 70);
--mineral-stone-700: oklch(0.82 0.018 70);
--mineral-clay-100: oklch(0.27 0.028 40);
--mineral-clay-300: oklch(0.36 0.028 40);
--mineral-clay-500: oklch(0.55 0.035 40);
--mineral-clay-700: oklch(0.82 0.035 40);
--mineral-rose-100: oklch(0.27 0.024 10);
--mineral-rose-300: oklch(0.36 0.024 10);
--mineral-rose-500: oklch(0.55 0.03 10);
--mineral-rose-700: oklch(0.82 0.03 10);
--mineral-sand-100: oklch(0.27 0.028 85);
--mineral-sand-300: oklch(0.36 0.028 85);
--mineral-sand-500: oklch(0.55 0.035 85);
--mineral-sand-700: oklch(0.82 0.035 85);
--mineral-moss-100: oklch(0.27 0.028 120);
--mineral-moss-300: oklch(0.36 0.028 120);
--mineral-moss-500: oklch(0.55 0.035 120);
--mineral-moss-700: oklch(0.82 0.035 120);
--mineral-sage-100: oklch(0.27 0.024 160);
--mineral-sage-300: oklch(0.36 0.024 160);
--mineral-sage-500: oklch(0.55 0.03 160);
--mineral-sage-700: oklch(0.82 0.03 160);
--mineral-fog-100: oklch(0.27 0.02 220);
--mineral-fog-300: oklch(0.36 0.02 220);
--mineral-fog-500: oklch(0.55 0.025 220);
--mineral-fog-700: oklch(0.82 0.025 220);
--mineral-slate-100: oklch(0.27 0.024 262);
--mineral-slate-300: oklch(0.36 0.024 262);
--mineral-slate-500: oklch(0.55 0.03 262);
--mineral-slate-700: oklch(0.82 0.03 262);
--mineral-heather-100: oklch(0.27 0.024 310);
--mineral-heather-300: oklch(0.36 0.024 310);
--mineral-heather-500: oklch(0.55 0.03 310);
--mineral-heather-700: oklch(0.82 0.03 310);
--gem-ruby-light: oklch(0.34 0.071 15);
--gem-ruby-deep: oklch(0.88 0.071 15);
--gem-topaz-light: oklch(0.34 0.059 72);
--gem-topaz-deep: oklch(0.88 0.059 72);
--gem-emerald-light: oklch(0.34 0.05 160);
--gem-emerald-deep: oklch(0.88 0.05 160);
--gem-tourmaline-light: oklch(0.34 0.042 195);
--gem-tourmaline-deep: oklch(0.88 0.042 195);
--gem-sapphire-light: oklch(0.34 0.067 262);
--gem-sapphire-deep: oklch(0.88 0.067 262);
--gem-amethyst-light: oklch(0.34 0.063 305);
--gem-amethyst-deep: oklch(0.88 0.063 305);
--on-gem: oklch(0.97 0.005 90);
--on-bright: oklch(0.25 0.02 265);
--grain: url("data:image/svg+xml;utf8,");
--glass-sheen: oklch(1 0 0 / 0.07);
}
.riso-flat {
position: relative;
background-image: var(--grain), linear-gradient(var(--surface, var(--card)), var(--surface, var(--card)));
background-size: 200px 200px, auto;
}
.riso-print {
position: relative;
isolation: isolate;
background: none;
}
.riso-print::before {
content: '';
position: absolute;
inset: 0;
z-index: -2;
border-radius: inherit;
pointer-events: none;
background-image: radial-gradient(circle, var(--overprint) 42%, transparent 46%);
background-size: var(--halftone-size) var(--halftone-size);
transform: translate(var(--offset-x), var(--offset-y));
}
.riso-print::after {
content: '';
position: absolute;
inset: 0;
z-index: -1;
border-radius: inherit;
pointer-events: none;
background-image: var(--grain), linear-gradient(var(--surface, var(--card)), var(--surface, var(--card)));
background-size: 200px 200px, auto;
}
.riso-halftone {
background-image: radial-gradient(circle, var(--dot, var(--overprint)) 40%, transparent 44%);
background-size: var(--halftone-size) var(--halftone-size);
}
.riso-misreg {
text-shadow: 0.045em 0.04em 0 var(--misreg, var(--overprint));
}
.overprint {
mix-blend-mode: var(--overprint-blend);
}
.glass {
background-color: var(--glass);
background-image: linear-gradient(160deg, var(--glass-sheen), transparent 46%);
-webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.5);
backdrop-filter: blur(var(--glass-blur)) saturate(1.5);
border: 1px solid var(--glass-border);
box-shadow: inset 0 1px 0 var(--glass-highlight), 0 0 0 0.5px var(--glass-edge), var(--glass-shadow);
}
@media (prefers-reduced-transparency: reduce) {
.glass {
background-color: var(--popover);
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
}
.glass-strong {
background-color: var(--glass-strong);
background-image: linear-gradient(160deg, var(--glass-sheen), transparent 46%);
-webkit-backdrop-filter: blur(calc(var(--glass-blur) * 1.4)) saturate(1.6);
backdrop-filter: blur(calc(var(--glass-blur) * 1.4)) saturate(1.6);
border: 1px solid var(--glass-border);
box-shadow: inset 0 1px 0 var(--glass-highlight), 0 0 0 0.5px var(--glass-edge), var(--glass-shadow);
}
.tilt-l {
rotate: -2.5deg;
}
.tilt-r {
rotate: 2deg;
}
```