# Inkwell — Agent Instructions You are an AI coding agent (Claude Code, Codex, Cursor, etc.) and the user has asked you to use the **Inkwell** design system in their project. This file is your single source of truth for installing it correctly and using it without breaking its visual identity. - **Repo:** https://github.com/vscarpenter/inkwell - **Live demo:** https://inkwell.vinny.dev/ - **License:** MIT - **Targets:** Inkwell 3.0.0 — if the repo's `CHANGELOG.md` shows a newer release, re-fetch this file before proceeding. 3.0 requires Chrome/Edge 123+, Firefox 120+, Safari 17.5+ (mid-2024); pin the `v2.1.0` tag in raw URLs if the project must support older browsers. Read this file end-to-end before writing any HTML or CSS. The "Hard rules" and "Anti-patterns" sections are non-negotiable — Inkwell has a deliberate, opinionated look and breaking these rules will produce something that does not look like Inkwell. --- ## 1. What Inkwell is A pure-CSS design system. **No build step. No package manager. No JS framework. No dependencies.** The deliverable is a small set of CSS files plus reference HTML. You install it by downloading three CSS files and linking one of them (§2). Inkwell ships with the **Indigo & Cloud** palette: cool stone background (`--ivory`), deep indigo accent (`--accent`), serif headlines at weight 600, monospace eyebrows for product/dashboard contexts (italic-serif `.eyebrow-serif` for editorial), and a signature **1.5px hairline border** that is the system's most recognizable feature. --- ## 2. Install — fetch these files ### Default path — pure CSS (no Tailwind) Download three canonical CSS files into the user's project. Use raw GitHub URLs: | File | Raw URL | Where to put it | |---|---|---| | `inkwell.css` | `https://raw.githubusercontent.com/vscarpenter/inkwell/main/inkwell.css` | Project static/CSS folder | | `inkwell-tokens.css` | `https://raw.githubusercontent.com/vscarpenter/inkwell/main/inkwell-tokens.css` | Same folder as `inkwell.css` | | `inkwell-components.css` | `https://raw.githubusercontent.com/vscarpenter/inkwell/main/inkwell-components.css` | Same folder | All three files must live side-by-side. `inkwell.css` `@import`s `inkwell-tokens.css` (unlayered) and `inkwell-components.css` (into `@layer inkwell`, so the user's own CSS always overrides Inkwell components). `tokens.css` is a deprecated alias of `inkwell.css` — only fetch it if the project already links that filename. Link `inkwell.css` from your `
`: ```html ``` That is the entire install. Do not run `npm install`, do not add a bundler step, do not create a PostCSS config. ### Tailwind v4 path — drop-in theme If the user's project uses **Tailwind v4 (October 2024 or later)**, fetch the Tailwind files and import the theme from the user's existing Tailwind entry CSS: | File | Raw URL | |---|---| | `inkwell-tokens.css` | `https://raw.githubusercontent.com/vscarpenter/inkwell/main/inkwell-tokens.css` | | `inkwell-components.css` | `https://raw.githubusercontent.com/vscarpenter/inkwell/main/inkwell-components.css` | | `inkwell-theme.css` | `https://raw.githubusercontent.com/vscarpenter/inkwell/main/inkwell-theme.css` | Keep the three files side by side, then add two lines to the user's Tailwind entry CSS (typically `app.css`, `globals.css`, or whatever their build points at), in this order: ```css @import "tailwindcss"; @import "./inkwell-theme.css"; ``` That activates: every Inkwell token as a Tailwind utility (`bg-accent`, `text-slate`, `border-accent`, `font-serif`, `text-display`, `border-hair`), Inkwell component classes (`.btn`, `.card`, …) inside `@layer components` so utilities can override them, and a `dark:` variant that honors Inkwell's `[data-theme]` toggle. You do not need `inkwell.css` (or the deprecated `tokens.css` alias) unless you also want the pure-CSS entry for non-Tailwind consumers. **Tailwind v3 is not supported.** v3 requires a JS preset. If the user is on v3, recommend upgrading to v4 or installing Inkwell via the default path without Tailwind utility coverage. Full Tailwind setup guide and conventions: [`TAILWIND.md`](TAILWIND.md) in the repo. Read it before writing Tailwind+Inkwell markup. ### Optional companion files (fetch only if asked) | File | When to fetch | |---|---| | `tokens.json` | User wants tokens for Style Dictionary or a Figma plugin | | `index.html` | User wants a starter template with navbar + theme toggle | | `preview.html` | User wants the full component showcase page | | `examples/tailwind.html` | User wants a live Tailwind v4 + Inkwell integration demo | | `examples/*.html` | User wants a specific page pattern. Exact filenames: `dashboard`, `docs`, `landing`, `search`, `pricing`, `settings`, `profile`, `auth-pattern`, `not-found`, `changelog`, `roadmap`, `article`, `forms` (all `.html`) | | `DESIGN_SYSTEM.md` | You need the canonical spec (token tables, component list, anti-patterns) | | `TAILWIND.md` | User is integrating with Tailwind v4 — read this in full before writing markup | The `examples/` pages link gallery-only assets (`demo.css`, `demo.js`) and carry a palette pre-paint snippet in ``. If you use one as a starting point, strip those references — the root `index.html` is the clean copy-paste starter. If the user wants a non-default palette, also fetch the relevant variant file from `variants/` (see §6) and load it after `inkwell.css`. ### Suggested fetch commands ```bash # Default install (pure CSS, no Tailwind) — three files mkdir -p public/css BASE=https://raw.githubusercontent.com/vscarpenter/inkwell/main curl -sSLo public/css/inkwell.css $BASE/inkwell.css curl -sSLo public/css/inkwell-tokens.css $BASE/inkwell-tokens.css curl -sSLo public/css/inkwell-components.css $BASE/inkwell-components.css # Tailwind v4 install — inkwell-tokens.css + inkwell-components.css from above, # plus the theme entry (inkwell.css is optional on this path) curl -sSLo public/css/inkwell-theme.css $BASE/inkwell-theme.css ``` Adjust the destination path to match the user's project layout (e.g. `static/`, `assets/`, `app/styles/`, etc.). If unsure, ask once or pick the conventional location for the framework in use. ### Common integration points Use the host app's existing static asset and global stylesheet conventions. Do not add tooling just to install Inkwell. | Project type | Put files here | Load it here | |---|---|---| | Static HTML | `css/` or `public/css/` | `` | | Next.js App Router | `public/css/` | `app/layout.tsx` with `` | | Next.js Pages Router | `public/css/` | `pages/_document.tsx` or `pages/_app.tsx` | | Vite / React | `public/css/` | `index.html`, or import from the app's existing global CSS | | Rails / Laravel / Django | Existing public/static CSS folder | Base layout template | For framework apps, prefer a global load path. Inkwell defines global tokens and component classes, so it should be available across routes rather than scoped to one component. --- ## 3. Hard rules — do not violate These are not stylistic preferences. They are the system. Breaking any of them produces something that is not Inkwell. 1. **Borders are `1.5px`, never `1px` or `2px`.** Always use the `--border` token. The 1.5px is retina-first by design — on non-retina displays it will render as 1px and `getComputedStyle` will report 1px. That is browser behavior, not a bug. Do not "fix" it with `box-shadow` workarounds. 2. **One accent only.** `--accent` is the single saturated brand hue. If a chart or data viz needs a second color, use `--olive` or `--sky`. Never introduce a second saturated accent. 3. **Tokens, never literal hex codes.** Component CSS must reference CSS custom properties. If you find yourself typing `#3B4A8C` in a stylesheet, stop and use `var(--accent)` instead. This rule is what makes palette swapping trivial. 4. **Type families have jobs, not preferences:** - `var(--serif)` → headings, stat numbers, italic emphasis, editorial primitives (lede, pullquote, byline-author, figure caption, `.eyebrow-serif`) - `var(--mono)` → file names, hex codes, byline metadata, table-numeric cells, `.eyebrow` for product/dashboard contexts. Signals "technical metadata." - `var(--sans)` → everything else Do not substitute one for another. 5. **Platform fonts only.** No Google Fonts, no `@font-face`, no webfont loaders. Stacks load instantly and produce zero FOUT. The serif stack leads with Iowan Old Style → Palatino → Source Serif Pro → Georgia (`ui-serif` was dropped in 1.4.0 — it resolves to wildly variable fonts per OS and couldn't be QA'd). 6. **Page background is `--ivory`, not white.** Body text is `--slate`, not pure black. Pure white + pure black collapses the cool-putty atmosphere. 7. **Every saturated color token must be defined in both light and dark.** If you add a new colored token, define a **lifted** (more luminous) value in the dark-mode block too. A color defined only at `:root` will look muddy on dark surfaces. 8. **Do not invent new accent token names.** Use `--accent` (and its derived tokens `--accent-d`, `--accent-tint`, etc.) everywhere. Palette switching works by overriding `--accent`; parallel token names break that mechanism. 9. **Accent as text → `--accent-ink`; accent as fill → `--accent` + `--on-accent` label.** Never put raw `--accent` text on any surface in a variant palette — use `--accent-ink`. Clay's coral and sage's green are too light to read, and `--accent-ink` is the token the variants darken to keep text AA. --- ## 4. Token cheat sheet The most-used tokens. Full list lives in `inkwell-tokens.css` (the file is well-commented — read it; `tokens.css` is a deprecated one-line alias of `inkwell.css`). Every color token is a single `light-dark(light, dark)` declaration; alpha tints derive from their base via `color-mix()`. **Surfaces & text** - `--ivory` — page background - `--paper` — card / panel surface - `--slate` — primary text - `--gray-100..700` — neutrals (cool putty, not warm beige) **Accent & semantic** - `--accent` / `--accent-d` / `--accent-tint` / `--accent-focus-ring` — indigo accent family (fills, tints, rings) - `--accent-ink` — use for accent-colored TEXT (links, tabs, badge text); `--accent` is for fills. Variants darken the ink to stay readable. - `--on-accent` — label color on accent fills (button labels, severity pills) - `--olive` — success / additions / second data-viz hue - `--olive-dark` — olive as text or solid fill (badge-success, stat deltas) - `--rust` — danger / deletions - `--sky` — alternate info / second data-viz hue **Type** - `--serif`, `--sans`, `--mono` — font stacks (platform-only; serif stack details in hard rule 5) - `--t-display`, `--t-h1`, `--t-h2`, `--t-h3`, `--t-lede`, `--t-body`, `--t-small`, `--t-caption`, `--t-eyebrow` — sizes **Borders & radius** - `--border` (1.5px solid `--gray-300`) — the signature outer frame - `--border-strong` (1.5px solid `--slate`) - `--border-hair` (1px solid `--gray-100`) — internal dividers inside a `--border` panel - `--border-rule` (1px solid `--gray-300`) — horizontal section rules - `--control-border` (1.5px solid `--gray-400`) — checkbox/radio/switch boundaries; functional state edges must clear 3:1, unlike decorative hairlines - `--r-xs`, `--r-sm`, `--r-md`, `--r-lg`, `--r-xl`, `--r-pill` — radii **Layout** - `--content-narrow` (820), `--content-default` (920), `--content-wide` (1120) — max-widths - `--page-pad-x` (24px) — horizontal page padding - `--z-base`, `--z-raised`, `--z-sticky`, `--z-overlay`, `--z-modal` — z-index scale - `--t-fast` (120ms), `--t-base` (150ms), `--t-slow` (300ms) — transitions --- ## 5. Component classes `inkwell-components.css` ships ready-made components (you get them automatically by linking `inkwell.css`). Use these classes verbatim — do not rename or re-style them in your own CSS unless you have a specific reason. | Class | Purpose | |---|---| | `.btn` (`-primary`, `-secondary`, `-ghost`, `-danger`; `:disabled` / `:active` / `.btn-sm` / `aria-busy="true"`) | Buttons, with disabled, pressed, small, and loading-spinner states. Pair `aria-busy="true"` with `disabled` from JS — CSS only blocks pointer events, not keyboard activation. | | `.input`, `.textarea`, `.select` (`.is-error`, `:disabled`) | Form controls | | `.field` (`.field-label`, `.field-help`, `.field-error`) | Vertical field group | | `.checkbox`, `.radio`, `.switch` | Selection controls | | `kbd` / `.kbd` | Keyboard chip | | `.badge` (neutral / accent / success / warning / danger) | Status pill labels | | `.alert` (`.is-info`, `.is-success`, `.is-warning`, `.is-danger`) | Flat-tinted system messages | | `.card` (`.is-link`) | Generic card; `.is-link` shifts only the border on hover — no lift, no shadow swap | | `.stat-card` (`.is-primary`) | Big-number metric tile; `.is-primary` marks the headline metric with a full 1.5px accent border | | `.tbl` | Table with sans headers and hairline rows | | `.tbl-scroll` | Overflow wrapper for `.tbl` — horizontal scroll on narrow viewports | | `.tldr` | Inverted callout (dark in light mode, light in dark) | | `.code-block` | Multi-line `` panel |
| `.dialog` | Native `