# Branding Branding an Elements app means repointing the accent tokens. There are two levels: a light-touch accent override, and a full brand ramp. Both go in `@layer tokens`, imported after `@elements/style`. ## The accent block Five tokens carry the brand: | Token | Role | |---|---| | `--accent` | The brand color | | `--accent-deep` | Hover, pressed, gradient end | | `--accent-soft` | Tinted accent backgrounds (selected rows, accent callouts) | | `--accent-ink` | Text and icons sitting on an `--accent` fill | | `--accent-edge` | Accent borders on tinted surfaces | Every accent-bearing component reads these. Set them once and buttons, focus rings, checkboxes, selected tabs, and accent surfaces all follow. ## Link color A bare `` is the one thing the accent block does not cover, because a link has to stay readable inside a dark panel or a brand-colored hero as well as on the page. It takes its lightness from the text around it and its color from two tokens of its own: | Token | Role | |---|---| | `--link-c` | Link chroma, roughly 0.10 to 0.18 for a saturated brand | | `--link-h` | Link hue in degrees, the same hue as your brand ramp | ```css :root { --link-c: 0.120; --link-h: 235; } ``` Leave them unset and links render as the surrounding ink a shade deeper, plus the underline. That is always legible, which is why it is the default, but it is not branded. See [base](../base) for how the adaptive color works. ## Light touch If you just want a brand color, set the accent block. In a scaffolded app the place for this is `app/shared/styles/vars.css` (imported by both the page and email baselines): ```css :root { --accent: #4a7bc4; --accent-deep: #2f5a9e; /* hover / pressed / gradient end */ --accent-soft: #eef3fb; /* tinted accent backgrounds */ --accent-ink: #ffffff; /* text on the accent fill */ } ``` `--accent` alone is enough to color the system. The soft and ink companions are needed for tinted regions (an accent callout, a selected-row background, text on an accent fill); skip them and components fall back to `--accent` everywhere, which works but reads flatter. You can also point fonts here in the same file: ```css :root { --font-sans: "Your Sans", ui-sans-serif, system-ui, sans-serif; --font-mono: "Your Mono", ui-monospace, monospace; } ``` ## Full brand ramp For a polished result across light and dark mode, define a full brand ramp and point the accent block at it. Copy `themes/customer-example.css` into `app/shared/styles/`, edit the values, and import it from `page.css` after `@elements/style`. The recipe has three steps. **Step 1: your brand ramp.** Anchor your brand color at 500 and fill in a 50–950 ramp. Match the lightness curve of the ramps in `themes/default.css` so your brand behaves like the status ramps (an OKLCH ramp generator seeded with your hex gets you there): ```css @layer tokens { :root { --brand-50: oklch(0.97 0.015 0); --brand-100: oklch(0.93 0.040 0); --brand-200: oklch(0.87 0.080 0); --brand-300: oklch(0.80 0.130 0); --brand-400: oklch(0.72 0.180 0); --brand-500: oklch(0.62 0.220 0); /* your brand color */ --brand-600: oklch(0.54 0.215 0); --brand-700: oklch(0.46 0.180 0); --brand-800: oklch(0.36 0.140 0); --brand-900: oklch(0.26 0.100 0); --brand-950: oklch(0.16 0.065 0); } } ``` **Step 2: repoint the accent block at the ramp.** This is the only block that does the branding work: ```css @layer tokens { :root { --accent: var(--brand-500); --accent-deep: var(--brand-700); --accent-soft: var(--brand-50); --accent-ink: var(--brand-900); --accent-edge: var(--brand-200); --focus: var(--accent); --focus-ring: 0 0 0 3px color-mix(in oklch, var(--focus) 40%, transparent); } } ``` **Step 2b (optional): the checkbox glyph.** The checkmark is an inline SVG data URI, so it can't read `--accent-ink`. If your `--accent-ink` isn't near-white, repoint `--checkbox-check` to a stroke matching it (copy the URL from `themes/default.css` and change the `stroke='%23…'` hex). **Step 3 (optional): dark-mode brand override.** Use a lighter ramp step on dark backgrounds so the color stays vibrant. Follow the same two-block pattern the default theme uses, the OS-preference block and the `data-theme` block, kept identical: ```css @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --accent: var(--brand-400); --accent-deep: var(--brand-300); --accent-soft: var(--brand-950); --accent-ink: var(--brand-100); --accent-edge: var(--brand-800); } } :root[data-theme="dark"] { --accent: var(--brand-400); --accent-deep: var(--brand-300); --accent-soft: var(--brand-950); --accent-ink: var(--brand-100); --accent-edge: var(--brand-800); } ``` ## The shipped example: themes/elements.css `themes/elements.css` is the canonical worked example: the Elements brand blue. It's opt-in, not part of the default entry, and follows exactly the recipe above: ```css @import "@elements/style"; @import "@elements/style/themes/elements"; ``` It defines an Elements-blue ramp (`--elements-blue-*`, anchored at `#49A9E7` / `#164C77`), repoints the accent block at it, updates `--focus` and `--focus-ring`, sets a white checkbox glyph (its `--accent-ink` is white in both modes), and adds the dark-mode accent override. Read it as a complete, real branding file.