Nine RealmsThe stave standing on a horizon line; its light is broken into nine ember dashes on the water below, one for each realm.

Nine realms. One name.

Brand guidelines · Version 1.0 · Sat 05 Sep 2026 · ninerealms.cc

01The idea

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

The household

Sees the stave, three realm names and plain descriptors. Never needs to decode a myth to find a film.

The operator

Sees host names, vendor names, the raven and the Watch state. Reads terse, timestamped copy.

Agents

Build surfaces from the tokens, the SVG library and these rules. A rule that is not written here does not exist.

02Architecture and naming

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.

LayerWhatExample
HouseNine Realms: the mark, wordmark, palette, type, voiceNine Realms
RealmA place name for one product, one size below the houseNine Realms · Asgard
DescriptorA plain word so the household never has to decode the realmMedia
VendorThe 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.

RealmProduct (descriptor)VendorHost
AsgardMediaPlexBragi
VanaheimRequestsOmbiSkidbladnir
MidgardHomeHome AssistantFensalir
BifrostIngress (keeps its name; a bridge, not a realm)private HTTPSbifrost
AlfheimNetworkUniFiUniFi
JotunheimVirtualisationProxmoxOdin
SvartalfheimContainers and automationDocker, PortainerSkidbladnir, Frigg
NiflheimStorage and backupsSynologyMímir
MuspelheimCompute and AIGPU, agentsproposed
HelheimArchive, 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

Nine Realms · Asgard, MediaProduct lockup: the mark, the house name, a middle dot, the realm name Asgard, and the descriptor Media on its own line.

Live · Asgard

Nine Realms · Asgard
Media

Live · Vanaheim

Nine Realms · Vanaheim
Requests

Live · Midgard

Nine Realms · Midgard
Home

Live · Heimdall

Nine Realms · Heimdall
The watch

Compact form · nav bars and 64 px headers

Nine Realms · Asgard
Media
Nine Realms · Vanaheim
Requests
Nine Realms · Midgard
Home
Nine Realms · Heimdall
The watch

Lockup rules

  1. Order is fixed: mark · house · middle dot · realm. House 800, realm 600, one size, one baseline.
  2. Descriptor on its own line: JetBrains Mono 500, 0.30 × name size, tracking 0.12 em, Smoke, capitals.
  3. 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.
  4. 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.
  5. One ink per lockup, never Ember, except the light path in the horizon form.
  6. 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.
  7. First appearance on any surface is the full lockup with descriptor; later mentions may say just the realm or just the descriptor.
  8. 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

ContextForm
Lockup, headerNine Realms · Asgard / Media
Household sentence"in Media", "Media is down"
Operator sentence"Media (Asgard) on Bragi", "Plex stopped at 02:14"
Domain, emailninerealms.cc, requests@ninerealms.cc, alerts@ninerealms.cc
Code, hostnames, device nameslowercase, in code: bragi, asgard
04Colour

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)

Black ice
#080C0F
Page ground
ground
Iron
#14191C
Cards, inputs
1.11 on Black ice · surface step
Ash
#2A2E31
Card borders, bars (decorative)
Black ice 1.43 · Iron 1.29
Ash line
#656A6D
Input borders, hairlines that mean something
Black ice 3.59 · Iron 3.24
Bone
#EFEAE2
Ink, display, the mark
Black ice 16.39 · Iron 14.79
Smoke
#A8A49E
Secondary text, descriptors
Black ice 7.92 · Iron 7.14
Smoke 2
#83807A
Footers, metadata, 11 px and above
Black ice 4.99 · Iron 4.50
Ember
#FF992B
Lit, primary action, the light path
Black ice 9.20 · Iron 8.30
Ember hot
#FFC151
Hover, highlight
Black ice 12.15 · Iron 10.96
Ember deep
#AC3500
Large fills only, never text on dark
Black ice 3.05 · Iron 2.75
Frost
#9ACDE2
In progress, links in tables
Black ice 11.41 · Iron 10.29
Pyre red
#F05940
Watch, down, danger
Black ice 5.80 · Iron 5.24

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
#EFF4F6
Page ground (light)
ground
White
#FFFFFF
Cards (light)
1.11 on Snow · surface step
Black ice
#080C0F
Ink, the mark
Snow 17.71 · White 19.63
Smoke deep
#5E5B56
Secondary text
Snow 6.10 · White 6.76
Ash line
#656A6D
Tertiary text, input borders
Snow 4.94 · White 5.47
Ash light
#C9CFD2
Card borders (decorative)
Snow 1.42 · White 1.57
Ember deep
#AC3500
Lit, primary action, links
Snow 5.80 · White 6.44
Ember deep hover
#8A2B00
Hover
Snow 7.81 · White 8.66
Frost deep
#056180
In progress, links in tables
Snow 6.26 · White 6.94
Pyre deep
#B5311B
Watch, down
Snow 5.54 · White 6.14

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.

TokenDark (identity)Light (derived)
--nr-bgBlack ice #080C0FSnow #EFF4F6
--nr-surfaceIron #14191CWhite #FFFFFF
--nr-borderAsh #2A2E31Ash light #C9CFD2
--nr-border-strongAsh line #656A6DAsh line #656A6D
--nr-ruleBone #EFEAE2Black ice #080C0F
--nr-inkBone #EFEAE2Black ice #080C0F
--nr-ink-2Smoke #A8A49ESmoke deep #5E5B56
--nr-ink-3Smoke 2 #83807AAsh line #656A6D
--nr-accent, --nr-link, --nr-state-litEmber #FF992BEmber deep #AC3500
--nr-accent-hover, --nr-link-hoverEmber hot #FFC151Ember deep hover #8A2B00
--nr-accent-inkBlack iceSnow
--nr-state-pulling, --nr-link-tableFrost #9ACDE2Frost deep #056180
--nr-state-waitingSmoke #A8A49ESmoke deep #5E5B56
--nr-state-watch, --nr-state-downPyre red #F05940Pyre deep #B5311B
--nr-focus-ring2 px gap, 2 px Ember hot2 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.

Lit
Ember / Ember deep · filledup, available, ready. Also IN MEDIA, UP
Pulling · 64 %
Frost / Frost deep · filledin progress
Needs a yes
Smoke / Smoke deep · filledwaiting on a person or a queue. Also QUEUED
Watch · 91 %
Pyre red / Pyre deep · outlinedthreshold crossed, still up, needs the operator
Down
Pyre red / Pyre deep · filled, plus a 2 px top border on the cardnot working

Filled 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 #000 or pure white text; the grounds are Black ice and Snow, the inks are Bone and Black ice.
05Typography

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

Ident · 112 · 900 · +0.06 em
Nine Realms
Hero · 84 · 900
The fire
is kept.
Display · 64 · 900
Black water
Title · 40 · 900 · −0.03 em
Media is down
Heading · 26 · 800
The raven's report
Card title · 22 · 800
Mímir · Volume 1
Section label · 15 · 800 · +0.02 em
Tonight in Media
Row title · 20 · 700
The Salt Road
Body · 16 · 400
Films go straight through. Series wait for one yes. Plex stopped at 02:14; back by 02:40. Nothing is lost.
Small body · 14
Add a drive or cut retention before 95 %, when Plex stops transcoding.
Metric · Mono 40 · 600
91 %
Button · Mono 12 · 700 · +0.18 em
Request
Metadata · Mono 12 · 500 · +0.10 em
Sat 05 Sep · 02:14 · Requested Tue
Label · Mono 11 · 600 · +0.16 em
Needs a yes · Pulling · Watch · Down

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

pxRoleFace
11label capsMono 600
12metadata, buttonsMono 400–700
14small body, card textArchivo 400–600
16bodyArchivo 400
20row titleArchivo 700
26headingExpanded 800
40title, metricExpanded 900 / Mono 600
64displayExpanded 900
84heroExpanded 900
112identExpanded 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 as 02:14, dates as SAT 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">
06Voice

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

  1. No exclamation marks. Ever. The sentence carries its own weight.
  2. No jokes, no winks, no emoji. Fun lives in the names and the pictures, not in the copy.
  3. 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.
  4. Name the time. "Back by 02:40", "Tonight", "requested Tue". Never "soon", "shortly", "ASAP".
  5. Say what happens next. Every notification ends with the next thing: a time, an action, or "Nothing to do".
  6. 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.
  7. Numbers are exact. "91 %", "+140 GB in seven days", "3 min". Not "almost full", "a while".
  8. 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.
  9. Status words are the system's words: Lit, Pulling, Needs a yes, Watch, Down, Resolved. Not "online", "healthy", "error", "oops".
  10. Never apologise, never boast. "Nothing is lost" beats "We're sorry" and "99.9 % uptime".

Register by surface

SurfaceRegisterSample
Household portalSecond 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 stepbelow
Operator consoleLabels, numbers, one imperativebelow
alerts@ incident mailSubject states the fact; body: what, when back, what is not affectedbelow
Status pagePresent tense, timestamped, the master line at the foot"Media is down. Bragi is restarting. Back by 02:40."
DocumentationSentence case, imperative headings, no marketing"Add a device. Approve a request."

The three sample copies

Household notification · push / requests@ninerealms.cc

Nine Realms · Requests
The Salt Road is in Media. Tonight, if you want it. Series still need one yes.

Operator alert · console / ops channel

Watch · Mímir (Synology NAS)
Volume 1 at 91 %. +140 GB in seven days. Add a drive or cut retention before 95 %, when Plex stops transcoding.

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

Subject · Media is down. Bragi restarting. Ongoing

Media is down. Bragi is restarting.

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.

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

LineRoleLives
The fire is kept.Master lineTitle card and idents, status page, alerts@ footer
Nine Realms. One watch.Operator lineOperator console (Heimdall), the raven's report panel, ops channel
Nine realms. One name.Document lineGuideline cover, About page
Name it. It's on tonight.Requests hero, a product line not a house lineRequests 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

UseNot
in Media, in Requests, at Homeon Plex, in Ombi, in HA (household copy)
needs a yespending approval
pullingdownloading, syncing, processing
lit, uponline, healthy, green
watchwarning, alert level 2
downoutage, incident (in household copy)
the operatoradmin, sysadmin, support team
tonight, by 02:40soon, shortly, in a bit
07Mascot

The raven

Nine Realms ravenA single raven in profile 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. A solid straight-cut silhouette with no eye.

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

24 · minimum
40 · alerts@ header
120 · empty state
200 · idents
  • 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.
Odin
3 up · 1 pulling · 1 needs you
Watermark · 240 px and above · 8 % opacity
Nothing to report
Every job that went out last night came back. Next run 03:00.
Empty state · 120 px on a hairline

Where it may appear

SurfaceHow
Operator consoleIdentity 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 cardsPerched 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 header40 px, Bone, standing on the header rule
Documentation and the guidelineChapter 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.

08Applications

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

Nine Realms · Vanaheim
Requests
K

Name it.
It's on tonight.

Films go straight through. Series wait for one yes.

Tonight in Media
The Salt Road
Film · 2025 · Requested Tue
In Media
Northern Waters
Series · S2 · 6 episodes
Pulling · 64 %
Iron Coast
Series · S1 · Requested Sat
Needs a yes
Requests runs on Ombi · Media plays in Asgard (Plex)ninerealms.cc
  • 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 REQUESTS in 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-vignette and 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

Nine Realms · Odin
Proxmox host
Prod
Odin
3 up · 1 pulling · 1 needs you
RefreshSnapshotConsole
Bragi
Plex · VM 101
14 d
Up since Fri 22 Aug. CPU 31 %.
Lit
Fensalir
Home Assistant · VM 103
64 %
Pulling 2026.9.1. Done by 03:12.
Pulling · 64 %
Mímir
Synology NAS
91 %
Volume 1. +140 GB in seven days. Add a drive before 95 %.
Watch · 91 %
The raven's report
Nine Realms. One watch.
02:00Backups: 6 of 6 jobs finished. 212 GB to Mímir. Nothing to do.
02:40Bragi restarted after Plex stopped at 02:14. Media up. Nothing lost.
03:15Storage: Mímir volume 1 crossed 90 %. Watch until a drive is added.
Resolved 02:40 · Media is up. Bragi restarted. Timeline ↗Odin · Frigg · Mímir · Skidbladnir · Fensalir · Bragi
  • 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-outlined PROD tag 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 TIMELINE link; 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@

Media is down. Bragi is restarting.

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.

The fire is kept.ninerealms.cc
alerts@ · dark-native · subject "Media is down. Bragi restarting. Ongoing"
Media is up. Bragi restarted.

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 fire is kept.ninerealms.cc
alerts@ · light fallback · subject "Media is down. Bragi restarting. Resolved"

The Salt Road is in Media.

Tonight, if you want it. Series still need one yes.

Requested Tue · Film · 2025

Requests runs on Ombininerealms.cc
requests@ · product lockup PNG at 320 px wide · one bold line, one plain line, one next step
  • 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 / -light PNG lockups from logo/png/ because mail clients will not run SVG or web fonts.
  • requests@ header: logo/png/product-lockup-template-512-dark.png (or the -light twin) 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 beside ninerealms.cc.
  • Subject lines state the fact and the status: "Media is down. Bragi restarting. Ongoing" / "Resolved". No emoji, no brackets.

Status page

Nine Realms
Sat 05 Sep · 12:00 · All lit
Media
Asgard
Lit
Requests
Vanaheim
Lit
Home
Midgard
Lit
The fire is kept.
Everything lit · the horizon mark is the only Ember; Lit rows read in Bone
Nine Realms
Sat 05 Sep · 02:20 · 1 down
Media
Asgard
Down
Requests
Vanaheim
Lit
Home
Midgard
Lit
Media is down. Bragi is restarting. Back by 02:40.
Started 02:14 · Next word 02:40
The fire is kept.
Something down · plain mark in the header; the Down diamond replaces the Ember

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

favicon-16 · five cuts
favicon-32 · seven cuts
favicon · 48 · nine cuts
favicon-512 · app tile
Household portal tab only · Ember stroke
<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.

09Accessibility

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.
ModeApproved text pairingsForbidden
DarkBone, 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 fillsBone on Pyre red (2.82); Ember deep text on dark (3.05); any text on Ash
LightBlack 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 fillsEmber 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-stretch and uppercase are presentation: source text is title or sentence case so screen readers and search read "Nine Realms · Asgard".

Focus

Request Refresh Static rendering of --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 with aria-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

The Salt Roa
Not found · check the spelling
  • 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 is assertive.
  • 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.

10Motion

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

  1. 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.
  2. Once. A surface reveals when it loads and then is still. Hover and focus respond; nothing idles.
  3. 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.
  4. The light comes last. In any sequence, Ember appears after Bone: the mark, then the words, then the dashes or the button.
  5. 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

TokenValueUse
--nr-duration-fast150 mshover, focus, state word swap, button press
--nr-duration-base300 mspanels, rows, dialogs, nav
--nr-duration-slow600 mshero fade-up, the raven's single reveal
--nr-duration-ident4000 msthe title-card reveal, end to end
--nr-ease-outcubic-bezier(0.2, 0.7, 0.2, 1)anything appearing
--nr-ease-in-outcubic-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-base when 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.

Plate
Stave
Horizon rule
Nine Realms
Nine dashes
The fire is kept.
0.0 s1.02.03.04.0 s
TimeEvent
0.0–0.6 sBlack. The plate fades up to its held level; grain is on from frame one.
0.6–1.6 sThe stave fades up from 0 to Bone, 1 s, ease-out; no movement.
1.4–2.4 sThe horizon rule draws from the centre outward under the foot of the stave, 1 s, ease-in-out.
2.2–3.0 sNINE REALMS fades up, 0.8 s.
3.0–3.8 sThe 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 sHold. "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.
11Downloads

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 decisions
  • brand/index.mdLibrary map and quick reference
  • brand/guidelines/00-overview.mdBrand idea, architecture, taglines
  • brand/guidelines/01-logo.mdThe stave, the horizon form, sizes, clear space, don'ts
  • brand/guidelines/02-color.mdBoth palettes, the one-Ember rule, states, texture
  • brand/guidelines/03-typography.mdArchivo Expanded, Archivo, JetBrains Mono, the scale
  • brand/guidelines/04-voice.mdTone rules, the three samples, the Requests hero line
  • brand/guidelines/05-naming-and-lockups.mdRealm registry, lockup construction, vendor names
  • brand/guidelines/06-mascot.mdThe raven's places and its ban list
  • brand/guidelines/07-applications.mdPortal, console, email, status page, favicon, documentation
  • brand/guidelines/08-accessibility.mdWCAG 2.2 AA, focus, motion, colour independence
  • brand/guidelines/09-motion.mdOne reveal, durations, the 4 s ident
  • brand/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 above
  • brand/logo/nine-realms-mark-seven.svg · -on-dark.svg · -on-light.svgSeven cuts, 24–39 px
  • brand/logo/nine-realms-mark-five.svg · -on-dark.svg · -on-light.svgFive cuts, 23 px and below
  • brand/logo/nine-realms-mark-horizon.svg · nine-realms-mark-horizon-light.svgThe horizon form, 96 tile, explicit colours
  • brand/logo/nine-realms-wordmark.svg · -on-dark.svg · -on-light.svgNINE REALMS, outlined
  • brand/logo/nine-realms-lockup-horizontal.svg · -on-dark.svg · -on-light.svgMark beside the wordmark
  • brand/logo/nine-realms-lockup-stacked.svg · -on-dark.svg · -on-light.svgMark centred over the wordmark
  • brand/logo/product-lockup-template.svg · -on-dark.svg · -on-light.svgNINE REALMS · ASGARD over MEDIA, plain stave
  • brand/logo/product-lockup-horizon.svg · product-lockup-horizon-light.svgThe same on the horizon
  • brand/logo/favicon-16.svg · favicon-32.svg · favicon.svgFive, seven and nine cuts on a Black ice tile
  • brand/logo/png/Mark at 16–512, horizon at 64–512, wordmark and lockups at 512 and 1024, favicons at 16–512; -transparent, -dark, -light
  • brand/logo/README.mdFile index, construction, clear space, minimum sizes, misuse
  • brand/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 grid
  • brand/mascot/png/raven-{24,48,120,240}-{transparent,dark,light}.pngRaster exports at those heights
  • brand/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.001
  • brand/fonts/jetbrains-mono/JetBrainsMono[wght].ttf · JetBrainsMono-Italic[wght].ttf · OFL.txtJetBrains Mono variable, wght 100–800, v2.211
  • brand/fonts/fonts.cssOne @font-face per file
  • brand/fonts/README.mdRoles, self-hosting, the Google Fonts link, fallbacks

Tokens

  • brand/tokens/nine-realms.cssCustom properties, dark native, derived light, reduced motion
  • brand/tokens/tokens.jsonThe same values, W3C design-tokens shape
  • brand/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.


Nine Realms · brand guidelines · version 1.0 · Sat 05 Sep 2026 · The fire is kept.