Nine realms. One name.
Brand guidelines · Version 1.0 · Sat 05 Sep 2026 · ninerealms.cc
One stave, one fire, one watch
Nine Realms is the home lab's one brand. Every application, portal, email, status page and document carries the same mark, palette, type and voice; only the realm name and a plain-language descriptor change between products.
The stave
The mark: nine straight cuts, one axis, three pairs of branches, one pair of roots. It is Yggdrasil cut into wood, not drawn.
The fire
The colour: a cold world (Black ice, Bone, Smoke, Frost) with one warm light (Ember). Ember appears once per screen, as the one thing that is lit, and on the horizon form it is the mark's own light broken into nine dashes under the water.
The watch
Watch · 91 %
The voice and the operator's raven: short, present tense, timestamped, nothing goes unseen and nobody makes a fuss about it.
The register
A film-studio ident, not a software landing page: black, one light source, heavy confident capitals, material you can feel. Fun is allowed; cute is not. Dark mode is the identity; light mode is derived for documents and print.
The mood reference is a driving, relentless, ice-and-snow, hammer-of-the-gods rock record: energy and swagger in the rhythm, never in the adjectives. No lyrics, no band imagery.
Precedence
When two rules conflict, the order is: accessibility (09), then colour (04), then logo (03), then everything else. When a third-party skin cannot honour a rule, use the fallback named in the chapter and record the gap in the application's notes rather than inventing a variant.
Who this is for
Sees the stave, three realm names and plain descriptors. Never needs to decode a myth to find a film.
Sees host names, vendor names, the raven and the Watch state. Reads terse, timestamped copy.
Build surfaces from the tokens, the SVG library and these rules. A rule that is not written here does not exist.
A branded house
One master identity, product names swapped in, a plain-language descriptor. Every product is Nine Realms · <Realm> with a descriptor; nothing gets its own logo, palette or typeface. The realm is never heavier than the house.
| Layer | What | Example |
|---|---|---|
| House | Nine Realms: the mark, wordmark, palette, type, voice | Nine Realms |
| Realm | A place name for one product, one size below the house | Nine Realms · Asgard |
| Descriptor | A plain word so the household never has to decode the realm | Media |
| Vendor | The software, one step away, in footers and admin | "Media plays in Asgard (Plex)" |
The house name is always the two words "Nine Realms", title case in text, capitals in the lockup; never "9 Realms", "NineRealms" or "NR" in anything the household sees.
Realm registry
Household products only ever show Asgard, Vanaheim and Midgard. Hosts keep their existing god and object names next to the vendor. Adding a realm means adding a row here first; a product without a row has no name.
| Realm | Product (descriptor) | Vendor | Host |
|---|---|---|---|
| Asgard | Media | Plex | Bragi |
| Vanaheim | Requests | Ombi | Skidbladnir |
| Midgard | Home | Home Assistant | Fensalir |
| Bifrost | Ingress (keeps its name; a bridge, not a realm) | private HTTPS | bifrost |
| Alfheim | Network | UniFi | UniFi |
| Jotunheim | Virtualisation | Proxmox | Odin |
| Svartalfheim | Containers and automation | Docker, Portainer | Skidbladnir, Frigg |
| Niflheim | Storage and backups | Synology | Mímir |
| Muspelheim | Compute and AI | GPU, agents | proposed |
| Helheim | Archive, cold offline backup | — | — |
Heimdall is the operator console identity (Nine Realms · Heimdall, descriptor The watch): a person, not a place, so it never collides with the list. Helheim and Muspelheim never name household products. Muninn is reserved for a future archive product name and is never drawn.
The product lockup
Exact form: NINE REALMS · ASGARD with descriptor MEDIA in the files; "Nine Realms · Asgard" and "Media" as live text. Order is fixed: mark · house · middle dot U+00B7 · realm. House in Archivo Expanded 800, realm in Expanded 600, one size, one baseline, capitals at +0.06 em in the outlined files. Live text is title case so copy, search and screen readers read "Nine Realms · Asgard".
The outlined file · product-lockup-template.svg
Live · Asgard
Live · Vanaheim
Live · Midgard
Live · Heimdall
Compact form · nav bars and 64 px headers
Lockup rules
- Order is fixed: mark · house · middle dot · realm. House 800, realm 600, one size, one baseline.
- Descriptor on its own line: JetBrains Mono 500, 0.30 × name size, tracking 0.12 em, Smoke, capitals.
- Proportions (plain): mark tile 1.4 × name size; gap 0.3 × tile; the baseline 0.86 of the way down the tile so the roots fall below it; the descriptor's cap line 0.16 × tile below the tile foot.
- Proportions (horizon): tile 1.867 × name size (same stave size); the rule at 0.6875 of the tile continues unbroken under the whole name and ends 8 tile-units past it; the words stand on it; the descriptor sits in the water beside the light path, its top on the first dash.
- One ink per lockup, never Ember, except the light path in the horizon form.
- Compact form (nav bars, 64 px headers): seven-cut mark at 26 px, live name at 15 px (800 · 600), descriptor inline in mono caps after a 1 px Ash line hairline. Below 16 px name size drop the descriptor, then the realm, never the mark.
- First appearance on any surface is the full lockup with descriptor; later mentions may say just the realm or just the descriptor.
- To make another product's lockup, re-outline with the realm and descriptor swapped and nothing else moved; keep the files named
product-lockup-<realm>.svg.
Don't: no second dot; no "Nine Realms Asgard Media" run together; no descriptor inside the dot line; no realm in Ember; no raven in the lockup; no realm heavier or larger than the house; no vendor name in the lockup.
The vendor-name rule
Vendor names (Plex, Ombi, Proxmox, Portainer, Synology, UniFi, Home Assistant) stay visible where support and administration need them and nowhere else. They are not sub-brands. They live one step away from the lockup: in footers ("Requests runs on Ombi · Media plays in Asgard (Plex)"), in About, in admin headers ("Proxmox host"), and in incident mail ("Media runs on Plex; its host is Bragi"). Never in the lockup, never in a hero, never in a push notification's first line.
The asgard Syncthing collision
The tracked inventory already records asgard as a Syncthing device name (the home-side device name for the remote torrent and Syncthing peer whose home peer is Skidbladnir). That is a machine identity, not a product, and it stays as it is. The rules that keep the two apart:
- The brand never shows the device name. "Asgard" on a household surface means Media (Plex), full stop.
- Operator copy writes the device as code, lowercase:
asgard(Syncthing device), and the product in title case: Asgard (Media). Never "Asgard the device". - Nothing else new is named
asgard, in any case, on any host.
Writing the names
| Context | Form |
|---|---|
| Lockup, header | Nine Realms · Asgard / Media |
| Household sentence | "in Media", "Media is down" |
| Operator sentence | "Media (Asgard) on Bragi", "Plex stopped at 02:14" |
| Domain, email | ninerealms.cc, requests@ninerealms.cc, alerts@ninerealms.cc |
| Code, hostnames, device names | lowercase, in code: bragi, asgard |
The stave
Nine cuts on a 48-unit grid: an axis at x = 24 from y = 3 to 45, three pairs of branches rising at 45°, one pair of roots falling at 45°. Stroke 4.5, butt caps, miter joins.
Verticals and 45° diagonals only: no horizontals, no curves, because runes were cut against the grain and horizontals vanish in it. The roots fall below the baseline of any text the mark sits beside. One ink: Bone #EFEAE2 on dark, Black ice #080C0F on light. The mark is never Ember, except that the household portal's favicon may use an Ember stroke, and the horizon form carries Ember under the water. No redrawing: the path below is the mark; everything else is a copy.
M24 3V45M24 12L18 6M24 12L30 6M24 23L12 11M24 23L36 11M24 33L16 25M24 33L32 25M24 39L18 45M24 39L30 45
Construction · 48-unit grid, stroke 4.5
Clear space · one quarter of the mark's height, all sides
Clear space is a margin equal to one quarter of the mark's height (the spread of the root pair, 12 of 48 units) on all sides, measured from the ink; for the horizon form, from the ends of the rule. Nothing enters it: no text, no rule, no edge of a photo.
Size steps
Pick the file by rendered size, not by container. A 26 px header mark is the seven-cut file; a 16 px tab icon is favicon-16.svg.
| Size | Cuts | File |
|---|---|---|
| 40 px and above | Nine | nine-realms-mark.svg |
| 24–39 px | Seven (third branch pair dropped) | nine-realms-mark-seven.svg |
| 23 px and below | Five (axis, one branch pair, roots) | nine-realms-mark-five.svg |
The horizon form
The mark stands on a horizon and its light goes under the water. On a 96-unit tile: the stave at 1.5× with its foot on a 2-unit Bone rule at y = 66, and nine Ember dashes below the line, one per realm, widths 18 to 4 in an irregular order, opacity 1.0 to 0.32.
nine-realms-mark-horizon.svg · Bone and Ember
nine-realms-mark-horizon-light.svg · Black ice and Ember deep
- Never without the rule, never without all nine dashes.
- Hero and ident form only: title cards, splash screens, the guideline cover, alerts@ email headers at 120 px and above. Below 48 px the dashes smudge; below 32 px use the plain mark.
- The horizon form is that screen's one Ember. No Ember button, link or state shares the frame with it.
- Text set on the horizon is capitals, so nothing dips through the water.
Wordmark and master lockups
nine-realms-wordmark.svg: NINE REALMS in Archivo Expanded (wdth 125) weight 900 capitals, tracking +0.06 em, outlined. Never re-track, condense or stretch it; regenerate from the font if it must change. Do not set the wordmark as live text in a hero; use the file.
Wordmark
Horizontal lockup · tile 1.4 × name, gap 0.3 × tile, baseline 0.86
Stacked lockup · tile 2 × name, centred
Product lockup, horizon form · product-lockup-horizon.svg · 64 px name size and above
Minimum sizes
| Form | Minimum |
|---|---|
| Nine-cut mark | 40 px |
| Seven-cut mark | 24 px |
| Five-cut mark | 12 px (favicon-16 is the reference) |
| Horizon mark | 48 px tile; below 32 px use the plain mark |
| Wordmark | 80 px wide (about 9 px cap height) |
| Horizontal lockup | 120 px wide; below that use the mark alone |
| Product lockup, plain | 16 px name size; below that drop the descriptor, then the realm, never the mark |
| Product lockup, horizon | 64 px name size; it is a hero form |
Backgrounds
Flat Black ice or Iron (dark), Snow or white (light). On a photographic or generated plate, put the vignette from the Colour chapter between the plate and the mark so the ink measures at least 4.5:1 against what is behind it. The mark never sits on Ember, Frost or Pyre red fills.
Black ice
Iron
Snow
White
Misuse
Each of these has happened to another brand. None of them happens to this one.
- No outline, container, gradient, glow, drop shadow, bevel or rotation.
- No second colour on the mark; no Ember mark, no Frost mark.
- No raven on, in, or touching the mark or any lockup.
- No horizon form without its rule and nine dashes; no horizon form beside another Ember element.
- No nine-cut mark below 40 px; no horizon form below 48 px.
- No mixed-case wordmark, no hyphen or slash for the middle dot, no descriptor on the dot line.
- No redrawing. The path above is the mark; everything else is a copy.
The world is cold and there is one fire
Black ice for ground, Bone for ink, Smoke for what matters less, Frost for what is moving, and one warm Ember for the thing that is lit. Dark mode is the identity. Light mode is derived for documents, print and mail clients that force it.
Every ratio below is WCAG 2.2 relative luminance in sRGB, computed from tokens.json, not copied. Text needs 4.5:1 (3:1 at 24 px, or 18.66 px bold); non-text UI needs 3:1.
Dark (the identity)
Ink on fills: Black ice on Ember 9.20, on Ember hot 12.15, on Frost 11.41, on Smoke 7.92, on Pyre red 5.80. Bone on Ember deep 5.37. Never Bone on Pyre red (2.82).
Light (derived)
Snow #EFF4F6 is the ground, a cold white, not paper. Cards are white.
Snow on Ember deep 5.80, on Frost deep 6.26, on Pyre deep 5.54. The bright Ember #FF992B is graphic-only on light (1.92): the horizon light path, never text. Smoke 2 is not used on light (3.55).
Light-mode derivation
Light mode is not a second palette; it is the same semantic tokens pointed at derived values. Components use the semantic names; only logo and ident work uses the raw palette names.
| Token | Dark (identity) | Light (derived) |
|---|---|---|
--nr-bg | Black ice #080C0F | Snow #EFF4F6 |
--nr-surface | Iron #14191C | White #FFFFFF |
--nr-border | Ash #2A2E31 | Ash light #C9CFD2 |
--nr-border-strong | Ash line #656A6D | Ash line #656A6D |
--nr-rule | Bone #EFEAE2 | Black ice #080C0F |
--nr-ink | Bone #EFEAE2 | Black ice #080C0F |
--nr-ink-2 | Smoke #A8A49E | Smoke deep #5E5B56 |
--nr-ink-3 | Smoke 2 #83807A | Ash line #656A6D |
--nr-accent, --nr-link, --nr-state-lit | Ember #FF992B | Ember deep #AC3500 |
--nr-accent-hover, --nr-link-hover | Ember hot #FFC151 | Ember deep hover #8A2B00 |
--nr-accent-ink | Black ice | Snow |
--nr-state-pulling, --nr-link-table | Frost #9ACDE2 | Frost deep #056180 |
--nr-state-waiting | Smoke #A8A49E | Smoke deep #5E5B56 |
--nr-state-watch, --nr-state-down | Pyre red #F05940 | Pyre deep #B5311B |
--nr-focus-ring | 2 px gap, 2 px Ember hot | 2 px gap, 2 px Ember deep |
The tokens apply light mode under [data-theme="light"], and under prefers-color-scheme: light guarded by :root:not([data-theme="dark"]). This page stamps data-theme on the root; the toggle in the navigation flips it.
The one Ember
Ember appears once per screen, as one action or one state, never as decoration. On a screen that carries the horizon form, the light path is that Ember. A healthy operator surface is quiet: Smoke and Bone, one Ember at most. If two things want to be Ember, one of them is Bone.
Ember is a hue away from safety orange and two away from a certain streaming service. The discipline that keeps it ours is scarcity: never a fill behind text longer than a label, never a tint, never a gradient.
Semantic states
Always a word and a diamond (an 8 px square rotated 45°, the stave's cut). Colour never carries meaning alone. Watch and Down share a hue on purpose so the palette stays at six colours; the word and the diamond fill carry the difference.
IN MEDIA, UPQUEUEDFilled chips carry their -ink token for text on the fill:
LitPullingQueuedDown
Tokens: --nr-state-lit, --nr-state-pulling, --nr-state-waiting, --nr-state-watch, --nr-state-down, each with a -ink.
Surfaces and rules
Cards are Iron on Black ice (white on Snow) with a 1 px Ash (Ash light) border; the surface step alone is 1.11 and does not read without it. Section rules are 2 px Bone (Black ice). Input borders are Ash line in both modes. Horizontals mean water: use them as rules under things, not as dividers between everything.
Texture
Heroes, title cards and email headers may carry a generated or photographic plate (pyre on black water, fog, scorched wood, iron) under the radial vignette --nr-vignette and 7–10 % grain (--nr-grain-opacity). The vector system on top is flat and sharp. Every screen must stand on flat Black ice without the plate; the plate is never required for legibility. Plates are references until one is approved and its provenance recorded; the cover of this document uses the approved pyre plate.
Don'ts
- No green, no purple, no gold, no second warm colour.
- No Ember text on light, no Ember deep text on dark, no Bone on Pyre red.
- No tints, alpha washes or gradients of Ember; no Ember borders on cards except the Lit state's top rule.
- No pure black
#000or pure white text; the grounds are Black ice and Snow, the inks are Bone and Black ice.
Two families, three jobs
Archivo Expanded is the title card; Archivo is the reading face; JetBrains Mono is every label. Nothing else is installed. Both are SIL Open Font License 1.1 and travel with their licences in brand/fonts/.
Specimen
is kept.
Archivo Expanded (display)
font-family: "Archivo"; font-stretch: 125%; font-weight: 800–900;
text-transform: uppercase; letter-spacing: -0.035em; line-height: 0.92;
- Heroes at 84 px (weight 900), display at 64, titles at 40 (900, tracking −0.03 em, leading 0.95), headings at 26 (800), card titles at 22 (800, tracking −0.01 em), section labels at 15 (800, +0.02 em).
- The wordmark and lockups are the exception to negative tracking: caps at +0.06 em, outlined in the logo library. Do not set the wordmark as live text in a hero; use the file.
- Expanded caps eat width. Hero copy is written short, not set smaller: two lines at 84 px on a 1280 px screen, three at most. If it does not fit, cut words.
Archivo (reading)
font-family: "Archivo"; font-stretch: 100%; font-weight: 400–700;
- Body 16 px (17 px on wide screens), leading 1.4; documentation 1.5.
- Row titles 20 px weight 700, tracking −0.01 em, mixed case.
- Strong 600, never 700 inside body copy. Italic only for titles of works.
- Mixed case, sentence case. Reading text is never uppercase.
JetBrains Mono (labels)
font-family: "JetBrains Mono"; text-transform: uppercase;
- Labels, descriptors, nav items, status words, tags: 11 px, weight 600, tracking 0.14–0.18 em. 11 px is the floor; nothing is smaller.
- Metadata: 12 px, weight 400–500, tracking 0.10 em, Smoke.
- Descriptor in lockups: weight 500 at 0.30 × name size, tracking 0.12 em.
- Dashboard metrics: 40 px, weight 600, tracking −0.03 em, tabular figures (
font-variant-numeric: tabular-nums). - Buttons: 12 px, weight 700, tracking 0.18 em.
The scale
| px | Role | Face |
|---|---|---|
| 11 | label caps | Mono 600 |
| 12 | metadata, buttons | Mono 400–700 |
| 14 | small body, card text | Archivo 400–600 |
| 16 | body | Archivo 400 |
| 20 | row title | Archivo 700 |
| 26 | heading | Expanded 800 |
| 40 | title, metric | Expanded 900 / Mono 600 |
| 64 | display | Expanded 900 |
| 84 | hero | Expanded 900 |
| 112 | ident | Expanded 900, +0.06 em |
Colour of type
Bone for primary text, Smoke for secondary, Smoke 2 for footers at 11–12 px only (dark). Black ice, Smoke deep, Ash line on light. A word in Ember is a state or an action, never emphasis. Links are Ember in running text, Frost inside dense tables; both are also underlined or otherwise marked so colour is not the only cue.
Setting rules
- Headlines: uppercase, tight, no widows; balance with
text-wrap: balance. - Numbers: tabular in tables and metrics, proportional in prose. Percent sign spaced (
91 %), times as02:14, dates asSAT 05 SEP. - The middle dot
·(U+00B7) separates house and realm, and items in a metadata line; never a hyphen, slash or pipe. - No text shadows except the hero's 30 px Black ice shadow over a plate; no outlined text, no letterpress, no gradients on type.
- Line length: 60–75 characters for reading; hero lines no wider than 900 px.
Fallbacks
font-family: "Archivo", "Helvetica Neue", Arial, sans-serif;
font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
Where a third-party skin cannot honour font-stretch: 125% (Plex and Home Assistant slots), use Archivo at normal width and weight 800: still the family, slightly narrower. Where no web font loads (some mail clients), the fallback sans is acceptable; the lockup is an image there anyway.
Google Fonts, when not self-hosting:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap">
Short. Present tense. Name the time.
Verbs first, then what happens next. Confidence is brevity. Energy and swagger live in the rhythm, never in the adjectives.
Rules
- No exclamation marks. Ever. The sentence carries its own weight.
- No jokes, no winks, no emoji. Fun lives in the names and the pictures, not in the copy.
- No myth in operational copy. Realms are places; nobody "enters" one, nothing is "summoned", the raven does not "fly". The names carry the mythology so the sentences do not have to.
- Name the time. "Back by 02:40", "Tonight", "requested Tue". Never "soon", "shortly", "ASAP".
- Say what happens next. Every notification ends with the next thing: a time, an action, or "Nothing to do".
- Vendor and host names verbatim where support needs them: "Plex", "Bragi", "Mímir (Synology NAS)". Never in the lockup, always in the footer, About and operator copy.
- Numbers are exact. "91 %", "+140 GB in seven days", "3 min". Not "almost full", "a while".
- Second person for the household, plain words, one idea per sentence. Terse and timestamped for the operator, labels in mono caps, sentences in sentence case.
- Status words are the system's words: Lit, Pulling, Needs a yes, Watch, Down, Resolved. Not "online", "healthy", "error", "oops".
- Never apologise, never boast. "Nothing is lost" beats "We're sorry" and "99.9 % uptime".
Register by surface
| Surface | Register | Sample |
|---|---|---|
| Household portal | Second person, plain, warm by being useful | "Films go straight through. Series wait for one yes." |
| Push and requests@ | One bold line, one plain line, the next step | below |
| Operator console | Labels, numbers, one imperative | below |
| alerts@ incident mail | Subject states the fact; body: what, when back, what is not affected | below |
| Status page | Present tense, timestamped, the master line at the foot | "Media is down. Bragi is restarting. Back by 02:40." |
| Documentation | Sentence case, imperative headings, no marketing | "Add a device. Approve a request." |
The three sample copies
Household notification · push / requests@ninerealms.cc
Operator alert · console / ops channel
The operator alert says WATCH, not DOWN: a disk at 91 % is not down, and the Watch state exists so alerts stop lying.
Incident email · alerts@ninerealms.cc
Media is down. Bragi is restarting.
Plex stopped at 02:14. Back by 02:40. Nothing is lost. Requests and Home are up.
Reply to reach the operator. Media runs on Plex; its host is Bragi.
The full email layout, with header and footer, is in Applications.
The Requests hero line
Name it.
It's on tonight.
Films go straight through. Series wait for one yes.
This is the Requests hero and nothing else. It is a product line, not a house line: it does not go on the title card, the status page or in mail. Beneath it, one plain sentence: "Films go straight through. Series wait for one yes."
Taglines and where each lives
| Line | Role | Lives |
|---|---|---|
| The fire is kept. | Master line | Title card and idents, status page, alerts@ footer |
| Nine Realms. One watch. | Operator line | Operator console (Heimdall), the raven's report panel, ops channel |
| Nine realms. One name. | Document line | Guideline cover, About page |
| Name it. It's on tonight. | Requests hero, a product line not a house line | Requests hero only |
Each line stays in its home. The master line is the only one that appears under the wordmark. No line is set in Ember; no line takes an exclamation mark; none is used as a sentence inside body copy.
Words we use and words we do not
| Use | Not |
|---|---|
| in Media, in Requests, at Home | on Plex, in Ombi, in HA (household copy) |
| needs a yes | pending approval |
| pulling | downloading, syncing, processing |
| lit, up | online, healthy, green |
| watch | warning, alert level 2 |
| down | outage, incident (in household copy) |
| the operator | admin, sysadmin, support team |
| tonight, by 02:40 | soon, shortly, in a bit |
The raven
One raven. It goes out over the nine realms and comes back to report. It stands for persistence, memory and the watch: the agents and jobs that go out overnight and come back with news. It is a mascot layer over the master system, never the mark, and it belongs to the operator.
The drawing
A straight-cut silhouette, 49 cuts on a 120 × 100 grid, facing right, head lowered and thrust forward, straight bill with a hooked tip, throat hackles, hunched shoulders, folded wing, wedge tail angled down, perched on a line with two toes. No eye (an eye turns it into a pet), no feather cuts (the nine live in the stave), no curves. Those four features, the bill, the hackles, the shoulders and the tail, are what keep it a raven at 24 px. Nobody redraws it.
Ink and size
- One ink: Bone on dark, Black ice on light. Never Ember: the bird watches the fire, it is not the fire. No outline, shadow, glow or gradient.
- 24 px minimum. 40 px in the alerts@ header. 120 px as an empty-state figure. 200 px and above on idents. 240 px and above as a watermark at 6–10 % opacity.
- It always stands on something: a hairline, a 2 px rule, the horizon, or a card's top edge. Align the toes (viewBox
y = 72) to the top of that line. It faces right, toward the content, never flipped.
Where it may appear
| Surface | How |
|---|---|
| Operator console | Identity of the report panel ("The raven's report": what went out and came back overnight); watermark behind the console hero; empty-state figure when there is nothing to report |
| Idents and title cards | Perched on the horizon rule, left of the wordmark, 200 px and above, same ink as the mark. The only thing that stands on the horizon beside the stave |
| alerts@ email header | 40 px, Bone, standing on the header rule |
| Documentation and the guideline | Chapter openers and the About page |
Ban list
- Never in a lockup, never touching the stave, never as a favicon, app icon, or avatar for a person.
- Never on household surfaces smaller than a hero: no raven in Requests rows, Home tiles, Media splashes, buttons, badges or notifications. The household sees the stave.
- Never with an eye, a beak highlight, claws, an open wing, a second bird, a speech bubble, a hat, or any pose other than this one. If a surface needs a second pose, the answer is no.
- Never floating, never mirrored, never in Ember, never with an outline, drop shadow or glow, never on a photograph without the vignette.
- Never named in product copy ("Huginn", "Muninn"). Muninn is reserved for a future archive product name and is never drawn.
- Never animated beyond a single reveal; never a loading indicator.
Voice around the raven
The report panel it heads is titled "The raven's report" and subtitled "Nine Realms. One watch." Its rows are the overnight jobs and what they found, in the operator register. The copy never narrates the bird: it does not "return", "bring word" or "spread its wings". The panel reports; the bird stands there.
How the system lands
Tokens from tokens/nine-realms.css; assets from logo/ and mascot/; fonts from fonts/fonts.css. Templates (email HTML, header component, Ombi CSS starter, status page) follow these rules when they land in templates/.
Household portal · Requests, Media, Home
Name it.
It's on tonight.
Films go straight through. Series wait for one yes.
- Ground Black ice; 64 px header with a 1 px hairline (Bone at 14 %); page gutter 48 px.
- Header: seven-cut mark at 26 px, "Nine Realms · Vanaheim" at 15 px Expanded 800 · 600, descriptor
REQUESTSin mono caps after a 1 px Ash line hairline, nav in mono caps 11 px, a 32 px square initial for the signed-in person. - Hero: Expanded 900 at 84 px, two lines, over the plate mirrored so the fire sits clear of the headline, under
--nr-vignetteand 7 % grain. Below the hero line, one 17 px Smoke sentence and the search bar with the one Ember button (REQUEST, mono 12 px 700, Black ice on Ember). - Rows: 52 × 74 poster, 20 px title, 12 px mono metadata, status word and diamond on the right. Section heads: Expanded 800 15 px caps over a 2 px Bone rule.
- Footer: 11 px mono Smoke 2, "REQUESTS RUNS ON OMBI · MEDIA PLAYS IN ASGARD (PLEX)" left, "NINEREALMS.CC" right.
- No raven anywhere on the portal. Ember once: the request button, or a single Lit state if there is no button on screen. With the button on screen, the Lit row's word and diamond are Bone, as above.
Operator console · Heimdall; Odin, Frigg, Mímir views
- 60 px header, 32 px gutter, Iron-to-Black ice gradient behind the top 200 px with 6 % grain. Header text "Nine Realms · Odin" with the vendor descriptor (
PROXMOX HOST) and an Ember-outlinedPRODtag when the environment is production; the tag counts as the screen's Ember when no state is Lit. - Title Expanded 900 at 40 px caps; summary line in mono 12 px ("3 UP · 1 PULLING · 1 NEEDS YOU"); actions as mono 11 px buttons, the primary one Bone with Black ice text (not Ember).
- Cards: Iron, 1 px Ash border, 2 px top border in the state colour; title Expanded 800 at 22 px caps; vendor line mono 11 px; metric mono 40 px 600; a 3 px bar in the state colour; one 13 px sentence.
- Footer strip: resolved incidents as a Waiting diamond plus one sentence and a
TIMELINElink; host list in mono 11 px Smoke 2. - "The raven's report" panel and the raven watermark belong here; the console line is "Nine Realms. One watch."
Email · requests@ and alerts@
Plex stopped at 02:14. Back by 02:40. Nothing is lost. Requests and Home are up.
Started 02:14 · Affects Media (Asgard) · Unaffected Requests (Vanaheim), Home (Midgard) · Next word 02:40, or sooner.
Reply to reach the operator. Media runs on Plex; its host is Bragi.
Plex came back at 02:38. Nothing is lost. Nothing to do.
Started 02:14 · Resolved 02:38 · Affected Media (Asgard) · Duration 24 min.
Reply to reach the operator. Media runs on Plex; its host is Bragi.
The Salt Road is in Media.
Tonight, if you want it. Series still need one yes.
Requested Tue · Film · 2025
- Dark-native table layout on Black ice with Bone text, and a light fallback (Snow, Black ice ink, Ember deep accent) for clients that force light; both use the
-dark/-lightPNG lockups fromlogo/png/because mail clients will not run SVG or web fonts. - requests@ header:
logo/png/product-lockup-template-512-dark.png(or the-lighttwin) shown at 320 px wide. Body: one bold line, one plain line, one next step, Archivo or the fallback sans at 16 px. - alerts@ header:
logo/png/nine-realms-mark-horizon-128-dark.png(or larger) left, the raven (mascot/png/raven-48-dark.png, sized to 40 px) standing on the header rule, subject as Expanded caps. Footer line "The fire is kept." in mono 12 px besideninerealms.cc. - Subject lines state the fact and the status: "Media is down. Bragi restarting. Ongoing" / "Resolved". No emoji, no brackets.
Status page
One column on Black ice. Product rows with word-plus-diamond states; incidents in the operator register with timestamps; the master line "The fire is kept." at the foot in mono 12 px. Down cards take the Pyre red top border. The horizon mark heads the page at 96 px and is the only Ember when everything is Lit; when something is Down, the Down diamond is the Ember's replacement and the header uses the plain mark.
Favicon and app icons
<link rel="icon" type="image/svg+xml" href="/brand/logo/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/brand/logo/png/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/brand/logo/png/favicon-16.png">
<link rel="apple-touch-icon" href="/brand/logo/png/favicon-180.png">
<link rel="manifest" href="/manifest.webmanifest"> <!-- icons: favicon-192.png, favicon-512.png -->
<meta name="theme-color" content="#080C0F">
- The household portal tab may swap the Bone stroke for Ember; no other surface may. Operator tools keep Bone.
- Third-party apps that accept a custom icon (Plex, Ombi, Home Assistant companion) get
png/favicon-512.png; those that force a circle mask keep the mark centred and accept the cropped corners.
Documentation
- Light or dark per reader preference (
prefers-color-scheme), the same tokens either way. Reading face Archivo 16–17 px, leading 1.5, 60–75 characters. Headings Expanded 800 caps at 26 and 40 px. Code in JetBrains Mono 14 px on Iron (white on light) with a 1 px border. - The cover carries the horizon mark, the wordmark and "Nine realms. One name." Chapter openers may carry the raven at 120 px on a rule.
- Diagrams use the palette: Bone lines, Ember for the one highlighted path, Frost for flows in progress; never a second warm colour.
This document is built to those rules and is the reference for them.
WCAG 2.2 AA in both modes
These rules outrank every other chapter. Ratios are in tokens/README.md, computed, not copied.
Contrast
- Text is at least 4.5:1 against its ground; large text (24 px, or 18.66 px bold) at least 3:1; non-text UI (borders that mean something, icons, focus rings, state diamonds) at least 3:1.
- Text over a plate or photograph sits on the vignette; measure against the darkest and lightest pixels under the text, not the average.
| Mode | Approved text pairings | Forbidden |
|---|---|---|
| Dark | Bone, Smoke, Ember, Ember hot, Frost, Pyre red on Black ice or Iron; Smoke 2 on Black ice or Iron at 11 px and above in footers only; Black ice on Ember, Ember hot, Frost, Smoke, Pyre red fills; Bone on Ember deep fills | Bone on Pyre red (2.82); Ember deep text on dark (3.05); any text on Ash |
| Light | Black ice, Iron, Smoke deep, Ash line, Ember deep, Ember deep hover, Frost deep, Pyre deep on Snow or white; Snow or white on Ember deep, Frost deep, Pyre deep fills | Ember text on light (1.92); Smoke 2 on light (3.55); any text on Ash light |
Colour independence
- Every state is a word and a diamond; the diamond's fill (filled or outlined) and the word carry the meaning, colour is confirmation.
- Links in running text are underlined or sit in a mono-caps label with an arrow (
MEDIA ↗); colour alone never marks a link. - Charts and bars pair colour with a label or value; the Watch and Down states share a hue on purpose and are told apart by the word and the diamond, never by shade.
Watch · 91 %DownSame hue. Different word, different fill.
Type
- Nothing below 11 px; body 16 px; labels in mono caps get 0.14–0.18 em tracking so caps stay readable.
- Text scales: layouts survive 200 % zoom and a 320 px viewport without horizontal scrolling; hero copy wraps, it does not shrink below 40 px.
font-stretchand uppercase are presentation: source text is title or sentence case so screen readers and search read "Nine Realms · Asgard".
Focus
--nr-focus-ring: 2 px gap in the ground colour, 2 px ring in Ember hot (dark, 12.15) or Ember deep (light, 5.80).
- Every interactive element shows
--nr-focus-ring. The ring is never removed, never replaced by colour change alone, and never obscured by sticky headers (WCAG 2.4.11). - Focus order follows reading order; skip link first on every page.
- Hit targets are at least 24 × 24 px (2.5.8); buttons are 40 px tall on the portal, 32 px minimum in dense operator tables.
Motion
- Every duration in the tokens collapses to 0 ms under
prefers-reduced-motion: reduce; the title-card reveal becomes a cut to the final frame; the raven appears without rising. - Nothing flashes more than three times a second; grain is static, never animated. No autoplaying video plates; the ident is a still by default.
- No parallax on the household portal; no motion carries information that a word does not also carry.
Images and marks
- The SVG marks carry
role="img"with a<title>and<desc>; when a mark is decorative beside its live name, inline it witharia-hidden="true"so the name is read once. - The lockup files' outlined text is backed by the live string in the
<title>("Nine Realms · Asgard, Media"). - The raven is decorative on every surface and is hidden from assistive technology; the report panel's heading carries the meaning.
- Email: every image has alt text in the voice ("Nine Realms · Requests", "The stave on the horizon"); the message reads correctly with images off.
Forms and states
- Inputs have visible labels (mono caps above, not placeholder-only) and a 1 px Ash line border (3.59 dark, 4.94 light); errors add the Pyre red word beside the field, not only a red border.
- Status changes are announced (
aria-live="polite"on the status region); Down isassertive. - Timeouts, if any, are stated in the copy with the time.
Checking
Before a surface ships: run an automated audit (axe or Lighthouse) in both modes, tab through every screen, zoom to 200 %, and set prefers-reduced-motion. Record the results in the application's notes.
One light source, one reveal
Motion in this system is the fire catching: something appears once, from dark, and then holds. Nothing bounces, nothing loops, nothing decorates. The reduced-motion guard is built into the tokens.
Principles
- From dark. Things fade up from the ground, they do not slide in from the side. Opacity and a short rise (4–8 px) are the whole vocabulary.
- Once. A surface reveals when it loads and then is still. Hover and focus respond; nothing idles.
- Fast on the surface, slow on the ident. Interface motion is 150–300 ms; the hero fade is 600 ms; only the title card takes 4 s.
- The light comes last. In any sequence, Ember appears after Bone: the mark, then the words, then the dashes or the button.
- Nothing moves that a word could say. Progress is a number and a Frost bar, not a spinner; state changes swap the word and the diamond with a 150 ms crossfade.
Durations and easing
| Token | Value | Use |
|---|---|---|
--nr-duration-fast | 150 ms | hover, focus, state word swap, button press |
--nr-duration-base | 300 ms | panels, rows, dialogs, nav |
--nr-duration-slow | 600 ms | hero fade-up, the raven's single reveal |
--nr-duration-ident | 4000 ms | the title-card reveal, end to end |
--nr-ease-out | cubic-bezier(0.2, 0.7, 0.2, 1) | anything appearing |
--nr-ease-in-out | cubic-bezier(0.6, 0, 0.2, 1) | anything moving between two places |
Surface motion
- Hover: colour only (Ember to Ember hot, Smoke to Bone), 150 ms. No scale, no shadow, no underline animation.
- Press:
translateY(1px), 150 ms. Nothing else. - Rows and cards on load: fade from 0 to 1 with a 6 px rise, 300 ms, staggered 40 ms per row up to eight rows; after that everything appears at once.
- Dialogs and panels: fade and 8 px rise, 300 ms; the ground behind darkens to Black ice at 70 %.
- State change: the old word and diamond fade out and the new fade in, 150 ms; a Down state also draws its 2 px top border in over 300 ms.
- Progress: the Frost bar width moves with
--nr-duration-basewhen the number changes; the number changes instantly. - Grain is static. Plates are still images; no Ken Burns, no drifting fog.
The title-card reveal · 4 s
The ident, in order, on the pyre plate under the vignette. There is one reveal and it is not repeated; a loop is a still frame. The raven, when present, fades up with the rule at 1.4 s, already standing.
| Time | Event |
|---|---|
| 0.0–0.6 s | Black. The plate fades up to its held level; grain is on from frame one. |
| 0.6–1.6 s | The stave fades up from 0 to Bone, 1 s, ease-out; no movement. |
| 1.4–2.4 s | The horizon rule draws from the centre outward under the foot of the stave, 1 s, ease-in-out. |
| 2.2–3.0 s | NINE REALMS fades up, 0.8 s. |
| 3.0–3.8 s | The nine dashes appear top to bottom, 60 ms apart, each a 150 ms fade: the light going under the water. The dashes are the last thing on. |
| 3.8–4.0 s | Hold. "The fire is kept." may fade in at 3.6 s in mono caps below the wordmark. |
The raven
A single reveal: fade with a 6 px rise onto its line, 600 ms, ease-out. Never a flap, blink, head turn, walk or loop; never a loading indicator.
Reduced motion
Under prefers-reduced-motion: reduce every duration is 0 ms: surfaces appear in their final state, state changes cut, the ident is its final frame, and the raven is simply there. Stagger and rise are removed along with the fades. This is not a degraded mode; the still frame is the design.
Don'ts
- No spinners, skeleton shimmer, pulsing dots or breathing glows.
- No parallax, no scroll-triggered animation on household surfaces.
- No animated Ember: the light does not flicker, pulse or travel except in the ident's dash sequence.
- No motion longer than 600 ms outside the title card.
- No animated favicons, tab titles or cursor effects.
The library
Everything lives under brand/ in the yggdrasil repository. Files named without a colour suffix use currentColor; use the -on-dark / -on-light twins in <img>, email and CSS backgrounds.
Rules
brand/README.mdProject charter and the round-four decisionsbrand/index.mdLibrary map and quick referencebrand/guidelines/00-overview.mdBrand idea, architecture, taglinesbrand/guidelines/01-logo.mdThe stave, the horizon form, sizes, clear space, don'tsbrand/guidelines/02-color.mdBoth palettes, the one-Ember rule, states, texturebrand/guidelines/03-typography.mdArchivo Expanded, Archivo, JetBrains Mono, the scalebrand/guidelines/04-voice.mdTone rules, the three samples, the Requests hero linebrand/guidelines/05-naming-and-lockups.mdRealm registry, lockup construction, vendor namesbrand/guidelines/06-mascot.mdThe raven's places and its ban listbrand/guidelines/07-applications.mdPortal, console, email, status page, favicon, documentationbrand/guidelines/08-accessibility.mdWCAG 2.2 AA, focus, motion, colour independencebrand/guidelines/09-motion.mdOne reveal, durations, the 4 s identbrand/guidelines/nine-realms-brand-guidelines.htmlThis document
Logo
brand/logo/nine-realms-mark.svg·-on-dark.svg·-on-light.svgThe stave, nine cuts, 40 px and abovebrand/logo/nine-realms-mark-seven.svg·-on-dark.svg·-on-light.svgSeven cuts, 24–39 pxbrand/logo/nine-realms-mark-five.svg·-on-dark.svg·-on-light.svgFive cuts, 23 px and belowbrand/logo/nine-realms-mark-horizon.svg·nine-realms-mark-horizon-light.svgThe horizon form, 96 tile, explicit coloursbrand/logo/nine-realms-wordmark.svg·-on-dark.svg·-on-light.svgNINE REALMS, outlinedbrand/logo/nine-realms-lockup-horizontal.svg·-on-dark.svg·-on-light.svgMark beside the wordmarkbrand/logo/nine-realms-lockup-stacked.svg·-on-dark.svg·-on-light.svgMark centred over the wordmarkbrand/logo/product-lockup-template.svg·-on-dark.svg·-on-light.svgNINE REALMS · ASGARD over MEDIA, plain stavebrand/logo/product-lockup-horizon.svg·product-lockup-horizon-light.svgThe same on the horizonbrand/logo/favicon-16.svg·favicon-32.svg·favicon.svgFive, seven and nine cuts on a Black ice tilebrand/logo/png/Mark at 16–512, horizon at 64–512, wordmark and lockups at 512 and 1024, favicons at 16–512;-transparent,-dark,-lightbrand/logo/README.mdFile index, construction, clear space, minimum sizes, misusebrand/scripts/build-logo.pyRegenerates the outlined files from the fonts
Mascot
brand/mascot/raven.svg·raven-on-dark.svg·raven-on-light.svgThe raven, 120 × 100 gridbrand/mascot/png/raven-{24,48,120,240}-{transparent,dark,light}.pngRaster exports at those heightsbrand/mascot/README.mdPlacement rules and the ban list
Fonts
brand/fonts/archivo/Archivo[wdth,wght].ttf·Archivo-Italic[wdth,wght].ttf·OFL.txtArchivo variable, wdth 62–125, wght 100–900, v2.001brand/fonts/jetbrains-mono/JetBrainsMono[wght].ttf·JetBrainsMono-Italic[wght].ttf·OFL.txtJetBrains Mono variable, wght 100–800, v2.211brand/fonts/fonts.cssOne@font-faceper filebrand/fonts/README.mdRoles, self-hosting, the Google Fonts link, fallbacks
Tokens
brand/tokens/nine-realms.cssCustom properties, dark native, derived light, reduced motionbrand/tokens/tokens.jsonThe same values, W3C design-tokens shapebrand/tokens/README.mdComputed contrast tables for both modes
Not here yet
brand/templates/ (email HTML, header component, favicon HTML snippet, Ombi CSS starter, status page) is the remaining Round 4 deliverable and is built from this library.