diff --git a/docs/brand/brand-guide.md b/docs/brand/brand-guide.md index b7d9080..71f5cb4 100644 --- a/docs/brand/brand-guide.md +++ b/docs/brand/brand-guide.md @@ -19,8 +19,9 @@ stylesheet with the others: - **owl.local** ([`retina-gui`](https://github.com/offworldlabs/retina-gui)) — the node's own UI They read as one family, but each has its own voice. Two sit apart: the map is -the only dark surface, a Flightradar24-style operational console, and owl-os is -the only one that runs on hardware in someone's house rather than on a server. +the only dark surface, a Flightradar24-style operational console, and the only +one that themes, offering light alongside its default dark (§3); owl-os is the +only one that runs on hardware in someone's house rather than on a server. owl-os is the odd repository as well as the odd surface. The UI is authored in [`retina-gui`](https://github.com/offworldlabs/retina-gui) but shipped by @@ -53,7 +54,8 @@ blah2 rather than to any surface described here. The surfaces share a spine (a blue accent, green/amber status colours, a small uppercase micro-label, hairline rules) and then diverge in personality. The split -maps onto audience. Four are light; the map is dark. +maps onto audience. Four are light; the map is dark by default and can be +switched to light. | | **owl** — offworldlabs.com | **retina** — retina.fm | **dash** — dash.retina.fm | **map** — map.retina.fm | **owl-os** — owl.local | |---|---|---|---|---|---| @@ -63,11 +65,11 @@ maps onto audience. Four are light; the map is dark. | **Serif** | Source Serif 4, wt 400 | Fraunces, wt 600 | none | none | none | | **Sans** | Inter | DM Sans | system stack | Inter (only font) | Inter | | **Mono** | IBM Plex Mono | JetBrains Mono | SF Mono | none (generic) | JetBrains Mono | -| **Canvas** | warm paper `#f7f6f2` | warm paper `#fafaf9` | cool slate `#f1f5f9` | **navy `#0d1b2a`** | near-white warm `#fffdfb` | -| **Blue** | muted `#5b8dd9` | punchy `#2563eb` | `#3b82f6` → `#2563eb` | sky `#38bdf8` | `#2f8adc`, accents only | +| **Canvas** | warm paper `#f7f6f2` | warm paper `#fafaf9` | cool slate `#f1f5f9` | **navy `#0d1b2a`**, light `#f1f5f9` | near-white warm `#fffdfb` | +| **Blue** | muted `#5b8dd9` | punchy `#2563eb` | `#3b82f6` → `#2563eb` | sky `#38bdf8`, light `#3b82f6` | `#2f8adc`, accents only | | **Radius** | 4–6px | 8–20px | 4–8px | 3–10px | 6–14px | | **Buttons** | flat | lift + shadow | flat | flat | flat, primary is ink | -| **Dark UI** | none | one dark section | none | **fully dark** | none | +| **Dark UI** | none | one dark section | none | **dark by default**, light opt-in | none | A rough rule of thumb for a new page: **who is it for?** Reaching outward to the scientific or funding world reads as owl. Selling or explaining the kit reads as @@ -91,14 +93,16 @@ to carry into new work. - **A paper-like canvas.** Four of the five use a near-white background (warm on the marketing sites and owl-os, cool slate on the console) with near-black text; owl-os pushes furthest toward white at `#fffdfb`. The **map is the - exception**: it is fully dark navy with light slate text. So "light paper" is - the norm for anything that explains, sells or configures, and dark is reserved - for the live operational view. + exception**: dark navy with light slate text, and the only surface that + themes, since it carries the console's light palette as an option too (§3). So + "light paper" is the norm for anything that explains, sells or configures, and + dark is the default for the live operational view. - **A blue accent.** owl sits soft and desaturated, retina and dash land on the brighter `#2563eb`/`#3b82f6`, owl-os lands between them at `#2f8adc`, and the - map goes brighter still (sky `#38bdf8`) to carry on dark. Blue is the only - chromatic accent in the UI chrome; everything else is ink on canvas. (The map - adds an amber `#fbbf24` as a selection/focus highlight.) owl-os spends its blue + map goes brighter still (sky `#38bdf8`) to carry on dark, dropping back to + dash's `#3b82f6` when it is themed light. Blue is the only chromatic accent in + the UI chrome; everything else is ink on canvas. (The map adds an amber + `#fbbf24` as a selection/focus highlight.) owl-os spends its blue the most sparingly: the primary button is ink, and the accent is kept for focus rings, hover borders, selection washes and the one card that is _this_ node. - **Green and amber as status colours.** Green marks "live" / validated / ADS-B @@ -140,17 +144,32 @@ roles (semantics) are shared unless a surface overrides them. | Canvas | `#f7f6f2` | `#fafaf9` | `#f1f5f9` | `#0d1b2a` | `#fffdfb` | | Sunk surface | `#edecea` | `#f5f4f0` | `#f8fafc` | `#0f2035` | `#fbfaf8` | | Card / panel | `#ffffff` | `#ffffff` | `#ffffff` | `#132240` | `#ffffff` | -| Dark section | — | `#090904` / `#242422` | — | (all dark) | — | +| Dark section | — | `#090904` / `#242422` | — | (the dark theme) | — | | Ink (primary) | `#0e0e0c` | `#1a1a18` | `#0f172a` | `#e2e8f0` | `#13161c` | | Ink (muted) | `#444440` | `#6b6b63` | `#475569` | `#94a3b8` | `#494d54` | | Ink (subtle) | `#888882` | `#9c9c93` | `#94a3b8` | `#64748b` | `#83868c` | -| Border | `rgba(14,14,12,.1)` | `#e8e8e3` | `#e2e8f0` | `rgba(100,180,255,.12)` | `#eae7e4` | +| Border | `rgba(14,14,12,.1)` | `#e8e8e3` | `#e2e8f0` | `rgba(100,180,255,.14)` | `#eae7e4` | The marketing canvases are warm (a hint of yellow); the console is cool slate; the map inverts to dark navy. The map's ink ramp is the dark mirror of the console's slate ramp (`#94a3b8` / `#64748b` recur), and its hairlines are a blue-tinted translucent white rather than a solid grey. +**The map's column above is its dark theme, which is the default.** Its light +theme takes dash's values wholesale: canvas `#f1f5f9`, sunk `#f8fafc`, card +`#ffffff`, the slate ink ramp, border `#e2e8f0`. The switch is a `data-theme` +attribute on the surface root, and the base selector carries dark while the +attribute carries light, so the default cannot flash the other theme before the +attribute is stamped. Everything on the surface is written against the custom +properties, so the whole chrome inverts from that one block. + +The sunk tier is the one place the two are not mirror images, and the reason the +map needs a token the light surfaces can do without. On a light surface a +recessed region is made by letting the canvas show through, the canvas already +being darker than a card; the map's ramp inverts, so a recessed pane needs a +colour of its own. It pays for the left aircraft list and, on the Physics tab, +the scene, ground-truth and solver sections. + owl-os crosses the two: a warm canvas like the marketing sites, over a **cool** ink ramp like the console. It is also the only surface authored in **OKLCH** rather than hex (`oklch(0.20 0.012 260)` and so on), so its ramps are even @@ -168,14 +187,21 @@ thirty stacked rows from reading as a grid. |---|---|---|---|---|---| | Accent | `#5b8dd9` | `#2563eb` | `#3b82f6` | `#38bdf8` | `#2f8adc` | | Hover / strong | `#4a7cc8` | `#3b82f6` | `#2563eb` | `#7dd3fc` | `#1a7acb` | -| Wash | `rgba(91,141,217,.15)` | `rgba(37,99,235,.06)` | `rgba(59,130,246,.10)` | `rgba(56,189,248,.15)` | `#e3f4ff` (opaque) | +| Wash | `rgba(91,141,217,.15)` | `rgba(37,99,235,.06)` | `rgba(59,130,246,.10)` | `rgba(56,189,248,.16)` | `#e3f4ff` (opaque) | | Wash edge | — | `rgba(37,99,235,.15)` | — | — | `#c4daf2` | +| Tint (hover) | — | — | — | `rgba(56,189,248,.07)` | — | owl's blue is deliberately soft and low-contrast (an editorial choice, though it costs link legibility, see §10). retina and dash share the saturated blue, with dash resting one step lighter and hovering to retina's resting value. The map -pushes to a brighter sky-blue so the accent reads on navy. owl-os sits between -dash and the map, a shade cyan-ward of both. Five distinct blues in all. +pushes to a brighter sky-blue so the accent reads on navy, and takes dash's +value when themed light rather than adding a sixth. owl-os sits between dash and +the map, a shade cyan-ward of both. Five distinct blues in all. + +The map is the only surface with **two** accent washes. The tint is the wash at +hover strength and sits deliberately below the wash proper, so a hovered row and +a selected one stay apart instead of collapsing into the same fill (light: +`rgba(59,130,246,.05)` under `rgba(59,130,246,.10)`). Two things owl-os does differently with it. Its washes are **opaque tints**, not alpha overlays, so a wash keeps its colour over any ground it lands on rather @@ -194,19 +220,34 @@ region is bounded rather than bleeding into the page. The map adds an amber | Error | (unused) | `#ef4444` (red-500) | `#f43f5e` | `#e64343` | Same three roles, brightened a step on the dark map so they carry on navy, and -landing between the marketing and console sets on owl-os. Each pairs with a wash -(~10% on light, ~15% on dark; opaque on owl-os) for tinted pill backgrounds. The -console's charts extend the accent into a categorical palette (`#3b82f6, +landing between the marketing and console sets on owl-os. The map's light theme +takes the console's set unchanged. Each pairs with a wash (~10% on light, ~15% +on dark; opaque on owl-os) for tinted pill backgrounds. The console's charts +extend the accent into a categorical palette (`#3b82f6, #10b981, #f59e0b, #ef4444, #8b5cf6, #ec4899, #06b6d4, #84cc16, #f97316, #14b8a6`, with `#94a3b8` for an "others" slice); reuse that ordering for any new dashboard chart. The map's live data colours are a separate, radar-specific scheme, not these -status roles: "truth" (solver agreeing with ADS-B) is **teal `#2dd4bf`**, the -ground-truth dot is **cyan `#22d3ee`**, and radar detections run a **Doppler -gradient** from dark-blue approaching (`#1e3a8a`) through cyan at zero (`#22d3ee`) -to dark-red receding (`#991b1b`). Green there means coverage polygons, not truth. -See §8. +status roles, and the one part of the estate chosen by measurement rather than by +eye: each value is held to a contrast floor against its own basemap, and each +pair of marks to a CIEDE2000 distance from the others. The second is the +constraint that gets forgotten, and the one that binds here, because the four +track lanes all draw the same aircraft glyph and colour is the only thing telling +them apart. **Truth** (the ADS-B fix the solves are measured against) wears no +hue at all: it sits at the far end of the neutral ramp from the canvas, near-white +`#f8fafc` on dark and slate `#1e293b` on light, since it is the reference rather +than a fifth lane. A simulated target flying without a transponder is grey beside +it. Radar detections run a **Doppler gradient** from dark-blue approaching +(`#1e3a8a`) through a neutral slate at zero to dark-red receding (`#991b1b`), so +no radial motion reads as the absence of a direction rather than as a third +colour. Green there means coverage polygons, never truth. See §8. + +Both palettes carry the same keys, so a component asks for a role and gets the +value for whichever theme is drawn. The light theme is the tighter of the two: +a near-white ground leaves every category competing for the dark end of its hue, +where a dark ground admits the whole light end, so it is light that constrains +any new category. owl-os carries a domain palette of its own that no other surface has, because no other surface asks a person to pick a transmitter. **Broadcast band** is a @@ -280,20 +321,24 @@ settings, large enough not to read as a table. | | owl | retina | dash | map | owl-os | |---|---|---|---|---|---| -| Radius (default) | 4px | 12px | 8px | 6px | 10px | -| Radius (small) | 3px | 8px | 4px | 3px | 6px | -| Radius (large) | 6px | 20px | 12px | 10px | 14px | - -Crisp on owl, soft on retina, moderate on dash, tight on the map, second-softest -on owl-os. Borders are always 1px hairlines; nothing uses a heavy stroke. The map -builds elevation from backdrop-blur (20px on the detail panel, 14px on the -playback bar) and subtle shadow rather than cards, since its panels float over -the map. +| Radius (default) | 4px | 12px | 8px | 8px | 10px | +| Radius (small) | 3px | 8px | 4px | 4px | 6px | +| Radius (large) | 6px | 20px | 12px | 12px | 14px | + +Crisp on owl, soft on retina, moderate on dash and on the map, which take the +same scale, second-softest on owl-os. Borders are always 1px hairlines; nothing +uses a heavy stroke. The map's panels float over a moving basemap rather than +sitting on a page, so it is the one surface where a card carries a shadow as +standard (`--panel-shadow`), heavier on dark than on light because a soft shadow +does almost nothing there and the elevation has to come from the panel being +lighter than the canvas. The three-step scale is a fair summary for four of the surfaces and a -simplification for two. The map actually spends 2, 3, 4, 5, 6 and 10px in its -stylesheet plus 8 and 12px inline, and retina spends 5, 6, 8, 10, 12 and 20px, -with neither of its two button radii matching the 12px recorded as its default. +simplification for one. The map is now the closest to keeping to it: most of its +radius rules read `--radius` or `--radius-sm`, with 12px reserved for pills and a +scatter of 2–6px literals left over. retina is the outlier, spending 5, 6, 8, 10, +12 and 20px, with neither of its two button radii matching the 12px recorded as +its default. owl-os is the only surface with a real elevation scale: a hairline `shadow-sm` at rest, a 24px-blur `shadow-md` on hover and for the sticky save bar, and a @@ -333,10 +378,10 @@ limited to 120ms colour, border and shadow transitions on hover, a 150ms switch throw, and a 2px nudge on a card's arrow. Nothing on the page moves unless it was touched, which is reasonable for a settings surface someone reaches when something needs fixing, and the reason its one animated component, the simulator, -is also the only place on any surface that checks `prefers-reduced-motion` before -starting. Everything else across all five surfaces still runs its loops -unguarded; the `tokens.css` `.reveal` helper adds the guard, and new work should -keep it. +checks `prefers-reduced-motion` before starting. The map guards its whole +surface with a single reduced-motion block, and owl's `/learn` page carries its +own; the two marketing home pages still run their loops unguarded. The +`tokens.css` `.reveal` helper adds the guard, and new work should keep it. --- @@ -348,15 +393,15 @@ pattern, check it exists on the surface you are building for. | | owl | retina | dash | map | owl-os | |---|---|---|---|---|---| -| Form controls | **none** | **none** | inline, ad hoc | a few, ad hoc | a real set | +| Form controls | **none** | **none** | inline, ad hoc | one shared rule | a real set | | Tables | none | none | yes | none | one | | Modal / dialog | none | none | **native `confirm()`** | one | three | | Toasts | none | none | none | yes | none | | Tabs | none | none | one page | app shell only | yes | | Icons | 36px, part-filled | Unicode glyphs | 24px, stroke 2 | inline SVG | 24px, stroke 1.6 | | Framework | none | none | none | none | Bootstrap 5.3 | -| Custom properties | yes | yes | yes | **none** | yes | -| `:focus` styling | none | none | **none** | one rule | inputs only | +| Custom properties | yes | yes | yes | yes, themed | yes | +| `:focus` styling | none | none | **none** | whole surface | inputs only | The two marketing sites have no `
`, ``, `